Skip to content

Commit

Permalink
fix(PowerStation): Fix UI not reflecting current core count in some s…
Browse files Browse the repository at this point in the history
…ituations.

- Fix dbus proxy watch blocking main thread.
- Update label whenever min/max/value properties change.
  • Loading branch information
pastaq committed Nov 13, 2023
1 parent 46e5c4c commit ff29eb7
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 25 deletions.
30 changes: 21 additions & 9 deletions core/global/dbus_manager.gd
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func _process(_delta: float):
func _process_message(msg: DBusMessage) -> void:
# Try looking up the well-known name of the message sender
var known_names := get_names_for_owner(msg.get_sender())

# Try constructing the resource path to the proxy and see if it exists
for known_name in known_names:
var res_path := "dbus://" + known_name + msg.get_path()
Expand All @@ -63,7 +63,10 @@ func _process_message(msg: DBusMessage) -> void:
continue
logger.debug("Found proxy to send message signal to at: " + res_path)
var proxy := load(res_path) as Proxy
var send_signal := func(message: DBusMessage):
if not proxy:
logger.warn("Failed to load proxy from resource cache: " + res_path)
continue
var send_signal := func(message: DBusMessage) -> void:
proxy.message_received.emit(message)
send_signal.call_deferred(msg)
break
Expand Down Expand Up @@ -116,7 +119,7 @@ func get_managed_objects(bus: String, path: String) -> Array[ManagedObject]:
var obj_data := objs_dict[obj_path] as Dictionary
var object := ManagedObject.new(obj_path, obj_data)
objects.append(object)

return objects


Expand All @@ -128,10 +131,15 @@ func get_names_for_owner(owner: String) -> PackedStringArray:
var name_owner := dbus_proxy.get_name_owner(name)
if name_owner == owner:
names.append(name)

return names


func _to_string() -> String:
var bus_string := "System" if bus_type == BUS_TYPE.SYSTEM else "Session"
return "<DBusManager#{0}>".format([bus_string])


## A Proxy provides an interface to call methods on a DBus object.
class Proxy extends Resource:
signal message_received(msg: DBusMessage)
Expand All @@ -141,14 +149,15 @@ class Proxy extends Resource:
var path: String
var rules := PackedStringArray()
var logger := Log.get_logger("DBusProxy")

var thread: SharedThread = load("res://core/systems/threading/system_thread.tres")

func _init(conn: DBus, bus: String, obj_path: String) -> void:
_dbus = conn
bus_name = bus
path = obj_path
message_received.connect(_on_property_changed)
if watch(IFACE_PROPERTIES, "PropertiesChanged") != OK:
logger.warn("Unable to watch " + obj_path)
thread.exec(watch.bind(IFACE_PROPERTIES, "PropertiesChanged"))


func _on_property_changed(msg: DBusMessage) -> void:
if not msg:
Expand Down Expand Up @@ -186,7 +195,7 @@ class Proxy extends Resource:
return null

return args[0]

## Get all properties for the given interface
func get_properties(iface: String) -> Dictionary:
var response := call_method(IFACE_PROPERTIES, "GetAll", [iface], "s")
Expand All @@ -205,7 +214,10 @@ class Proxy extends Resource:
)
rules.append(rule)
logger.debug("Adding watch rule: " + rule)
return _dbus.add_match(rule)
var err := _dbus.add_match(rule)
if err != OK:
logger.error("Unable to watch " + path)
return err


## A ManagedObject is a simple structure used with GetManagedObjects
Expand Down
56 changes: 51 additions & 5 deletions core/systems/threading/shared_thread.gd
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var thread: Thread
var mutex := Mutex.new()
var tid := -1
var running := false
var executing_task: ExecutingTask
var nodes: Array[NodeThread] = []
var process_funcs: Array[Callable] = []
var scheduled_funcs: Array[ScheduledTask] = []
Expand Down Expand Up @@ -74,7 +75,7 @@ func set_priority(value: int) -> int:
if LinuxThread.get_tid() != thread_id:
logger.debug("Set thread priority was called from another thread")
return await exec(set_priority.bind(value))

# Set the thread priority if this function was called from the SharedThread
var err := LinuxThread.set_thread_priority(value)
if err == OK:
Expand Down Expand Up @@ -178,12 +179,12 @@ func _run() -> void:
tid = LinuxThread.get_tid()
mutex.unlock()
logger.info("Started thread with thread ID: " + str(LinuxThread.get_tid()))

# If the nice value isn't default, reassign the thread priority
if niceness != 0:
if await set_priority(niceness) != OK:
logger.warn("Unable to set niceness on thread: " + name)

# TODO: Fix unsafe thread operations
Thread.set_thread_safety_checks_enabled(false)
var exited := false
Expand Down Expand Up @@ -238,23 +239,29 @@ func _process(delta: float) -> void:
for process in process_loops:
if not is_instance_valid(process.get_object()):
continue
_set_executing_task(ExecutingTask.from_callable(process))
process.call(delta)
_set_executing_task(null)

# Process nodes with _thread_process
for node in process_nodes:
if not is_instance_valid(node):
continue
_set_executing_task(ExecutingTask.from_node_thread(node))
node._thread_process(delta)

_set_executing_task(null)

# Call any one-shot thread methods
for method in process_methods:
if not is_instance_valid(method.get_object()):
continue
_set_executing_task(ExecutingTask.from_callable(method))
_async_call(method)
mutex.lock()
one_shots.erase(method)
mutex.unlock()

_set_executing_task(null)

# Call any scheduled methods
for task in process_scheduled:
var current_time := Time.get_ticks_msec()
Expand All @@ -263,17 +270,33 @@ func _process(delta: float) -> void:
var method := task.method as Callable
if not is_instance_valid(method.get_object()):
continue
_set_executing_task(ExecutingTask.from_callable(method))
method.call()
mutex.lock()
scheduled_funcs.erase(task)
mutex.unlock()
_set_executing_task(null)


func _async_call(method: Callable) -> void:
var ret = await method.call()
emit_signal.call_deferred("exec_completed", method, ret)


## Returns the currently executing task
func get_executing_task() -> ExecutingTask:
self.mutex.lock()
var task := self.executing_task
self.mutex.unlock()
return task


func _set_executing_task(task: ExecutingTask) -> void:
self.mutex.lock()
self.executing_task = task
self.mutex.unlock()


## Returns the target frame time in microseconds of the SharedThread
func get_target_frame_time() -> int:
return int((1.0 / target_tick_rate) * 1000000.0)
Expand All @@ -284,3 +307,26 @@ class ScheduledTask:
var start_time: int
var wait_time_ms: int
var method: Callable


## Container for holding information about the currently executing task
class ExecutingTask:
var object: String
var method: String
var args: Array

static func from_callable(callable: Callable) -> ExecutingTask:
var task := ExecutingTask.new()
task.object = str(callable.get_object())
task.method = callable.get_method()
task.args = callable.get_bound_arguments()
return task

static func from_node_thread(node: NodeThread) -> ExecutingTask:
var task := ExecutingTask.new()
task.object = node.get_path()
task.method = "_thread_process"
return task

func _to_string() -> String:
return "{0}.{1}({2})".format([self.object, self.method, str(self.args)])
3 changes: 2 additions & 1 deletion core/systems/threading/watchdog_thread.gd
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ func _check_frame_time(thread: SharedThread) -> void:
var target_time_us := get_target_frame_time(thread.target_tick_rate)
if time_since_us > (target_time_us * warn_after_num_missed_frames):
var time_since := time_since_us / 1000000.0
logger.warn("Thread '" + thread.name + "' has been blocked for {0} seconds".format([time_since]))
var task := thread.get_executing_task()
logger.warn("Thread '" + thread.name + "' has been blocked by {0} for {1} seconds".format([task, time_since]))


## Returns the target frame time in microseconds of the WatchdogThread
Expand Down
31 changes: 21 additions & 10 deletions core/ui/common/quick_bar/powertools_menu.gd
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func _ready() -> void:
apply_timer.start()
power_profile_dropdown.item_selected.connect(on_dropdown_changed)
thermal_profile_dropdown.item_selected.connect(on_dropdown_changed)

# Toggle visibility when the GPU freq manual toggle is on
var on_manual_freq := func() -> void:
# Immediately apply manual GPU frequency so we can read the min/max
Expand All @@ -119,7 +119,7 @@ func _ready() -> void:
gpu_freq_max_slider.value = card.clock_value_mhz_max

gpu_freq_enable.pressed.connect(on_manual_freq)

# Setup dropdowns
power_profile_dropdown.clear()
power_profile_dropdown.add_item("Max Performance", 0)
Expand All @@ -128,7 +128,7 @@ func _ready() -> void:
thermal_profile_dropdown.add_item("Balanced", 0)
thermal_profile_dropdown.add_item("Performance", 1)
thermal_profile_dropdown.add_item("Silent", 2)

# Set the initial values
_on_profile_loaded(performance_manager.current_profile)

Expand Down Expand Up @@ -173,17 +173,28 @@ func _on_profile_loaded(profile: PerformanceProfile) -> void:
if not power_station.supports_power_station():
logger.info("Unable to load performance profile. PowerStation not detected.")
return

var core_count := 1
if hardware_manager.cpu:
core_count = hardware_manager.cpu.core_count

logger.debug("Updating UI with loaded performance profile")
# Keep track of the currently loaded profile
current_profile = profile
# Update all UI components based on the loaded profile

# Update CPU UI components based on the loaded profile
profile_loading = true
cpu_boost_button.button_pressed = profile.cpu_boost_enabled
smt_button.button_pressed = profile.cpu_smt_enabled
if smt_button.button_pressed:
cpu_cores_slider.max_value = core_count
else:
var cores := core_count / 2
if cpu_cores_slider.value > cores:
cpu_cores_slider.value = cores
cpu_cores_slider.max_value = cores
cpu_cores_slider.value = profile.cpu_core_count_current
smt_button.pressed.emit()

# Update GPU UI components
tdp_slider.value = profile.tdp_current
tdp_boost_slider.value = profile.tdp_boost_current
gpu_freq_enable.button_pressed = profile.gpu_manual_enabled
Expand All @@ -210,10 +221,10 @@ func _setup_interface() -> void:
if node == Control:
(node as Control).visible = false
return

# Configure visibility for all components
wait_label.visible = false

# Configure CPU components
if power_station.cpu:
var cpu := power_station.cpu
Expand All @@ -225,7 +236,7 @@ func _setup_interface() -> void:
else:
cpu_cores_slider.max_value = cpu.cores_count / 2
cpu_cores_slider.visible = true

# Configure GPU components
if power_station.gpu:
var card := _get_integrated_card()
Expand Down
1 change: 1 addition & 0 deletions core/ui/components/slider.gd
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func _ready() -> void:
drag_started.emit()
slider.drag_ended.connect(on_drag_started)
var on_changed := func():
label_value.text = str(slider.value)
changed.emit()
slider.changed.connect(on_changed)

Expand Down

0 comments on commit ff29eb7

Please sign in to comment.