From 4c0424724a6f05a71cea3144bc446657d36d6d1d Mon Sep 17 00:00:00 2001 From: Evan Perry Grove Date: Fri, 9 Feb 2024 13:21:22 -0600 Subject: [PATCH] Fix CLI help bug, add support for sysfs/drm --- lib/sensething.rb | 26 ++++++- lib/sensething/cli.rb | 1 + lib/sensething/nvidia/smi.rb | 1 + lib/sensething/sysfs/cpufreq.rb | 26 +++---- lib/sensething/sysfs/drm.rb | 127 +++++++++++++++++++++++++++++++- 5 files changed, 166 insertions(+), 15 deletions(-) diff --git a/lib/sensething.rb b/lib/sensething.rb index a791031..c23532c 100644 --- a/lib/sensething.rb +++ b/lib/sensething.rb @@ -4,9 +4,17 @@ require_relative 'sensething/nvidia' require_relative 'sensething/cli' require_relative 'sensething/timestamp' +require 'pathname' module SenseThing def self.discover_devices(&block) + discover_hwmon_devices(&block) + discover_cpufreq_devices(&block) + NvidiaSmi::SmiDevice.enumerate_gpus(&block) + discover_drm_devices(&block) + end + + def self.discover_hwmon_devices Dir.glob('/sys/class/hwmon/*').each do |path| dev = begin Sysfs::Hwmon.new(path) @@ -17,7 +25,9 @@ def self.discover_devices(&block) yield dev end + end + def self.discover_cpufreq_devices(&block) Dir.glob('/sys/devices/system/cpu/*/cpufreq') do |path| dev = begin Sysfs::Cpufreq.new(path) @@ -28,7 +38,21 @@ def self.discover_devices(&block) yield dev end + end - NvidiaSmi::SmiDevice.enumerate_gpus(&block) + def self.discover_drm_devices(&block) + Dir.glob('/sys/class/drm/*').each do |path| + path = Pathname.new(path).realpath + next unless path.join('gt').directory? + + dev = begin + Sysfs::Drm.new(path) + rescue StandardError => e + warn "Tried to access a device at #{path.inspect}, but threw an exception: #{e}" + warn e.backtrace + end + + yield dev + end end end diff --git a/lib/sensething/cli.rb b/lib/sensething/cli.rb index 4bb12d4..58a1626 100644 --- a/lib/sensething/cli.rb +++ b/lib/sensething/cli.rb @@ -1,4 +1,5 @@ require 'optparse' +require 'set' require 'io/console' module SenseThing diff --git a/lib/sensething/nvidia/smi.rb b/lib/sensething/nvidia/smi.rb index 1a0e521..5dbe44f 100644 --- a/lib/sensething/nvidia/smi.rb +++ b/lib/sensething/nvidia/smi.rb @@ -80,6 +80,7 @@ def self.enumerate_gpus end end end + rescue Errno::ENOENT # rubocop:disable Lint/SuppressedException end def each_sensor # rubocop:disable Metrics/CyclomaticComplexity diff --git a/lib/sensething/sysfs/cpufreq.rb b/lib/sensething/sysfs/cpufreq.rb index aba4433..122ab36 100644 --- a/lib/sensething/sysfs/cpufreq.rb +++ b/lib/sensething/sysfs/cpufreq.rb @@ -28,13 +28,13 @@ def self.parse_attr_by_name(path) name = path.basename.to_s case name when 'scaling_cur_freq' - FrequencyValue.new(path) + CpuFrequencyValue.new(path) when 'scaling_min_freq' - FrequencyMin.new(path) + CpuFrequencyMin.new(path) when 'scaling_max_freq' - FrequencyMax.new(path) + CpuFrequencyMax.new(path) when 'scaling_governor' - Governor.new(path) + CpuGovernor.new(path) end end @@ -70,13 +70,13 @@ def initialize(device, attrs) @device = device attrs.each do |a| case a - when FrequencyMin + when CpuFrequencyMin @min_attr = a - when FrequencyMax + when CpuFrequencyMax @max_attr = a - when FrequencyValue + when CpuFrequencyValue @value_attr = a - when Governor + when CpuGovernor @governor_attr = a end end @@ -117,26 +117,26 @@ def summary def detail result = [] result << "value: #{value_attr.path}" if value_attr - result << "governor: #{governor_attr.path}" if governor_attr + result << "CpuGovernor: #{governor_attr.path}" if governor_attr result << "min: #{min_attr.path}" if min_attr result << "max: #{max_attr.path}" if max_attr result.join("\n") end end - class FrequencyValue < CpufreqAttribute + class CpuFrequencyValue < CpufreqAttribute include Megahertz end - class FrequencyMin < CpufreqAttribute + class CpuFrequencyMin < CpufreqAttribute include Megahertz end - class FrequencyMax < CpufreqAttribute + class CpuFrequencyMax < CpufreqAttribute include Megahertz end - class Governor < CpufreqAttribute + class CpuGovernor < CpufreqAttribute def fetch @val = read.strip end diff --git a/lib/sensething/sysfs/drm.rb b/lib/sensething/sysfs/drm.rb index 33494b7..342a53e 100644 --- a/lib/sensething/sysfs/drm.rb +++ b/lib/sensething/sysfs/drm.rb @@ -4,6 +4,131 @@ require_relative 'attribute' require_relative 'device' -# TODO module Sysfs + class DrmAttribute < Attribute + module Megahertz + def fetch + @val = Float(read) + end + + def unit + 'MHz' + end + + def same_sensor?(_other) + true # for drm, each 'device' represents a single sensor + end + end + end + + class Drm < Device + def self.parse_attr_by_name(path) + path = Pathname.new(path.to_s) unless path.is_a? Pathname + name = path.basename.to_s + case name + when 'gt_cur_freq_mhz' + DrmFrequencyValue.new(path) + when 'gt_min_freq_mhz' + DrmFrequencyMin.new(path) + when 'gt_max_freq_mhz' + DrmFrequencyMax.new(path) + when 'gt_boost_freq_mhz' + DrmFrequencyBoost.new(path) + end + end + + def create_sensor(attrs) + DrmSensor.new(self, attrs) + end + + protected + + def discover_attributes + attrs = [] + @path.each_child do |pn| + if (attr = self.class.parse_attr_by_name(pn)) + attrs << attr + end + end + @attrs = attrs + end + + def discover_name + @name = path.basename + end + end + + class DrmSensor < SenseThing::Sensor + attr_reader :device, :min_attr, :max_attr, :value_attr, :boost_attr + + def initialize(device, attrs) + super() + @device = device + attrs.each do |a| + case a + when DrmFrequencyValue + @value_attr = a + when DrmFrequencyMin + @min_attr = a + when DrmFrequencyMax + @max_attr = a + when DrmFrequencyBoost + @boost_attr = a + end + end + end + + def fetch + value_attr&.fetch + end + + def value(fetch: false) + value_attr&.value(fetch: fetch) + end + + def minimum + min_attr&.value + end + + def maximum + max_attr&.value + end + + def unit + value_attr&.unit + end + + def name + "#{device.name}/frequency" + end + + def summary + "Graphics Frequency (drm/#{device.path.basename})" + end + + def detail + result = [] + result << "value: #{value_attr.path}" if value_attr + result << "min: #{min_attr.path}" if min_attr + result << "max: #{max_attr.path}" if max_attr + result << "boost: #{boost_attr.path}" if boost_attr + result.join("\n") + end + end + + class DrmFrequencyValue < DrmAttribute + include Megahertz + end + + class DrmFrequencyMin < DrmAttribute + include Megahertz + end + + class DrmFrequencyMax < DrmAttribute + include Megahertz + end + + class DrmFrequencyBoost < DrmAttribute + include Megahertz + end end