summaryrefslogtreecommitdiffstats
path: root/tdecore/tdehardwaredevices.cpp
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-04-08 16:13:09 -0500
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-04-08 16:13:09 -0500
commit81dacc29a4cd8094350939191b7f35037c4439ee (patch)
tree0eae84897d49e616fc2d755e3ef83a31ca4eed22 /tdecore/tdehardwaredevices.cpp
parent8f76b98ccc30b7d0b574ce50ba602de4f2126cb6 (diff)
downloadtdelibs-81dacc29a4cd8094350939191b7f35037c4439ee.tar.gz
tdelibs-81dacc29a4cd8094350939191b7f35037c4439ee.zip
Add detailed CPU information gathering to the TDE hardware library
Diffstat (limited to 'tdecore/tdehardwaredevices.cpp')
-rw-r--r--tdecore/tdehardwaredevices.cpp277
1 files changed, 269 insertions, 8 deletions
diff --git a/tdecore/tdehardwaredevices.cpp b/tdecore/tdehardwaredevices.cpp
index c73acc748..24afe695f 100644
--- a/tdecore/tdehardwaredevices.cpp
+++ b/tdecore/tdehardwaredevices.cpp
@@ -27,6 +27,7 @@
#include <klocale.h>
#include <kconfig.h>
#include <ktempfile.h>
+#include <ksimpledirwatch.h>
#include <kstandarddirs.h>
#include <libudev.h>
@@ -767,6 +768,76 @@ bool TDEStorageDevice::unmountDevice(TQString* errRet, int* retcode) {
return false;
}
+TDECPUDevice::TDECPUDevice(TDEGenericDeviceType::TDEGenericDeviceType dt, TQString dn) : TDEGenericDevice(dt, dn) {
+}
+
+TDECPUDevice::~TDECPUDevice() {
+}
+
+double &TDECPUDevice::frequency() {
+ return m_frequency;
+}
+
+void TDECPUDevice::setFrequency(double fr) {
+ m_frequency = fr;
+}
+
+double &TDECPUDevice::minFrequency() {
+ return m_minfrequency;
+}
+
+void TDECPUDevice::setMinFrequency(double fr) {
+ m_minfrequency = fr;
+}
+
+double &TDECPUDevice::maxFrequency() {
+ return m_maxfrequency;
+}
+
+void TDECPUDevice::setMaxFrequency(double fr) {
+ m_maxfrequency = fr;
+}
+
+double &TDECPUDevice::transitionLatency() {
+ return m_transitionlatency;
+}
+
+void TDECPUDevice::setTransitionLatency(double tl) {
+ m_transitionlatency = tl;
+}
+
+TQString &TDECPUDevice::governor() {
+ return m_governor;
+}
+
+void TDECPUDevice::setGovernor(TQString gr) {
+ m_governor = gr;
+}
+
+TQString &TDECPUDevice::scalingDriver() {
+ return m_scalingdriver;
+}
+
+void TDECPUDevice::setScalingDriver(TQString dr) {
+ m_scalingdriver = dr;
+}
+
+TQStringList &TDECPUDevice::dependentProcessors() {
+ return m_tiedprocs;
+}
+
+void TDECPUDevice::setDependentProcessors(TQStringList dp) {
+ m_tiedprocs = dp;
+}
+
+TQStringList &TDECPUDevice::availableFrequencies() {
+ return m_frequencies;
+}
+
+void TDECPUDevice::setAvailableFrequencies(TQStringList af) {
+ m_frequencies = af;
+}
+
TDEHardwareDevices::TDEHardwareDevices() {
// Initialize members
pci_id_map = 0;
@@ -808,12 +879,49 @@ TDEHardwareDevices::TDEHardwareDevices() {
m_mountScanNotifier = new TQSocketNotifier(m_procMountsFd, TQSocketNotifier::Exception, this);
connect( m_mountScanNotifier, TQT_SIGNAL(activated(int)), this, TQT_SLOT(processModifiedMounts()) );
+ // Read in the current cpu information
+ // Yes, a race condition exists between this and the cpu monitor start below, but it shouldn't be a problem 99.99% of the time
+ m_cpuInfo.clear();
+ TQFile cpufile( "/proc/cpuinfo" );
+ if ( cpufile.open( IO_ReadOnly ) ) {
+ TQTextStream stream( &cpufile );
+ while ( !stream.atEnd() ) {
+ m_cpuInfo.append(stream.readLine());
+ }
+ cpufile.close();
+ }
+
+// [FIXME 0.01]
+// Apparently the Linux kernel just does not notify userspace applications of CPU frequency changes
+// This is STUPID, as it means I have to poll the CPU information structures with a 0.5 second or so timer just to keep the information up to date
+#if 0
+ // Monitor for changed cpu information
+ // Watched directories are set up during the initial CPU scan
+ m_cpuWatch = new KSimpleDirWatch(this);
+ connect( m_cpuWatch, TQT_SIGNAL(dirty(const TQString &)), this, TQT_SLOT(processModifiedCPUs()) );
+#else
+ m_cpuWatchTimer = new TQTimer(this);
+ connect( m_cpuWatchTimer, SIGNAL(timeout()), this, SLOT(processModifiedCPUs()) );
+ TQDir nodezerocpufreq("/sys/devices/system/cpu/cpu0/cpufreq");
+ if (nodezerocpufreq.exists()) {
+ m_cpuWatchTimer->start( 500, FALSE ); // 0.5 second repeating timer
+ }
+#endif
+
// Update internal device information
queryHardwareInformation();
}
}
TDEHardwareDevices::~TDEHardwareDevices() {
+// [FIXME 0.01]
+#if 0
+ // Stop CPU scanning
+ m_cpuWatch->stopScan();
+#else
+ m_cpuWatchTimer->stop();
+#endif
+
// Stop mount scanning
close(m_procMountsFd);
@@ -946,6 +1054,158 @@ void TDEHardwareDevices::processHotPluggedHardware() {
}
}
+void TDEHardwareDevices::processModifiedCPUs() {
+ // Detect what changed between the old cpu information and the new information,
+ // and emit appropriate events
+
+ // Read new CPU information table
+ m_cpuInfo.clear();
+ TQFile cpufile( "/proc/cpuinfo" );
+ if ( cpufile.open( IO_ReadOnly ) ) {
+ TQTextStream stream( &cpufile );
+ while ( !stream.atEnd() ) {
+ m_cpuInfo.append(stream.readLine());
+ }
+ cpufile.close();
+ }
+
+ // Parse CPU information table
+ TDECPUDevice *cdevice;
+ cdevice = 0;
+ bool modified = false;
+
+ TQString curline;
+ int processorNumber = 0;
+ int processorCount = 0;
+ for (TQStringList::Iterator cpuit = m_cpuInfo.begin(); cpuit != m_cpuInfo.end(); ++cpuit) {
+ // WARNING This routine assumes that "processor" is always the first entry in /proc/cpuinfo!
+ curline = *cpuit;
+ if (curline.startsWith("processor")) {
+ curline.remove(0, curline.find(":")+1);
+ curline = curline.stripWhiteSpace();
+ processorNumber = curline.toInt();
+ cdevice = dynamic_cast<TDECPUDevice*>(findBySystemPath(TQString("/sys/devices/system/cpu/cpu%1").arg(processorNumber)));
+ }
+ if (curline.startsWith("model name")) {
+ curline.remove(0, curline.find(":")+1);
+ curline = curline.stripWhiteSpace();
+ if (cdevice->name() != curline) modified = true;
+ cdevice->setName(curline);
+ }
+ if (curline.startsWith("cpu MHz")) {
+ curline.remove(0, curline.find(":")+1);
+ curline = curline.stripWhiteSpace();
+ if (cdevice->frequency() != curline.toDouble()) modified = true;
+ cdevice->setFrequency(curline.toDouble());
+ }
+ if (curline.startsWith("vendor_id")) {
+ curline.remove(0, curline.find(":")+1);
+ curline = curline.stripWhiteSpace();
+ if (cdevice->vendorName() != curline) modified = true;
+ cdevice->setVendorName(curline);
+ if (cdevice->vendorEncoded() != curline) modified = true;
+ cdevice->setVendorEncoded(curline);
+ }
+ }
+
+ processorCount = processorNumber+1;
+
+ // Read in other information from cpufreq, if available
+ for (processorNumber=0; processorNumber<processorCount; processorNumber++) {
+ cdevice = dynamic_cast<TDECPUDevice*>(findBySystemPath(TQString("/sys/devices/system/cpu/cpu%1").arg(processorNumber)));
+ TQDir cpufreq_dir(TQString("/sys/devices/system/cpu/cpu%1/cpufreq").arg(processorNumber));
+ TQString scalinggovernor;
+ TQString scalingdriver;
+ double minfrequency = -1;
+ double maxfrequency = -1;
+ double trlatency = -1;
+ TQStringList affectedcpulist;
+ TQStringList frequencylist;
+ if (cpufreq_dir.exists()) {
+ TQString nodename = cpufreq_dir.path();
+ nodename.append("/scaling_governor");
+ TQFile scalinggovernorfile(nodename);
+ if (scalinggovernorfile.open(IO_ReadOnly)) {
+ TQTextStream stream( &scalinggovernorfile );
+ scalinggovernor = stream.readLine();
+ scalinggovernorfile.close();
+ }
+ nodename = cpufreq_dir.path();
+ nodename.append("/scaling_driver");
+ TQFile scalingdriverfile(nodename);
+ if (scalingdriverfile.open(IO_ReadOnly)) {
+ TQTextStream stream( &scalingdriverfile );
+ scalingdriver = stream.readLine();
+ scalingdriverfile.close();
+ }
+ nodename = cpufreq_dir.path();
+ nodename.append("/scaling_min_freq");
+ TQFile minfrequencyfile(nodename);
+ if (minfrequencyfile.open(IO_ReadOnly)) {
+ TQTextStream stream( &minfrequencyfile );
+ minfrequency = stream.readLine().toDouble()/1000.0;
+ minfrequencyfile.close();
+ }
+ nodename = cpufreq_dir.path();
+ nodename.append("/scaling_max_freq");
+ TQFile maxfrequencyfile(nodename);
+ if (maxfrequencyfile.open(IO_ReadOnly)) {
+ TQTextStream stream( &maxfrequencyfile );
+ maxfrequency = stream.readLine().toDouble()/1000.0;
+ maxfrequencyfile.close();
+ }
+ nodename = cpufreq_dir.path();
+ nodename.append("/cpuinfo_transition_latency");
+ TQFile trlatencyfile(nodename);
+ if (trlatencyfile.open(IO_ReadOnly)) {
+ TQTextStream stream( &trlatencyfile );
+ trlatency = stream.readLine().toDouble()/1000.0;
+ trlatencyfile.close();
+ }
+ nodename = cpufreq_dir.path();
+ nodename.append("/affected_cpus");
+ TQFile tiedcpusfile(nodename);
+ if (tiedcpusfile.open(IO_ReadOnly)) {
+ TQTextStream stream( &tiedcpusfile );
+ affectedcpulist = TQStringList::split(" ", stream.readLine());
+ tiedcpusfile.close();
+ }
+ nodename = cpufreq_dir.path();
+ nodename.append("/scaling_available_frequencies");
+ TQFile availfreqsfile(nodename);
+ if (availfreqsfile.open(IO_ReadOnly)) {
+ TQTextStream stream( &availfreqsfile );
+ frequencylist = TQStringList::split(" ", stream.readLine());
+ availfreqsfile.close();
+ }
+ }
+
+ // Update CPU information structure
+ if (cdevice->governor() != scalinggovernor) modified = true;
+ cdevice->setGovernor(scalinggovernor);
+ if (cdevice->scalingDriver() != scalingdriver) modified = true;
+ cdevice->setScalingDriver(scalingdriver);
+ if (cdevice->minFrequency() != minfrequency) modified = true;
+ cdevice->setMinFrequency(minfrequency);
+ if (cdevice->maxFrequency() != maxfrequency) modified = true;
+ cdevice->setMaxFrequency(maxfrequency);
+ if (cdevice->transitionLatency() != trlatency) modified = true;
+ cdevice->setTransitionLatency(trlatency);
+ if (cdevice->dependentProcessors().join(" ") != affectedcpulist.join(" ")) modified = true;
+ cdevice->setDependentProcessors(affectedcpulist);
+ if (cdevice->availableFrequencies().join(" ") != frequencylist.join(" ")) modified = true;
+ cdevice->setAvailableFrequencies(frequencylist);
+ }
+
+ if (modified) {
+ for (processorNumber=0; processorNumber<processorCount; processorNumber++) {
+ TDEGenericDevice* hwdevice = findBySystemPath(TQString("/sys/devices/system/cpu/cpu%1").arg(processorNumber));
+ // Signal new information available
+ emit hardwareUpdated(hwdevice);
+ }
+ }
+}
+
void TDEHardwareDevices::processModifiedMounts() {
// Detect what changed between the old mount table and the new one,
// and emit appropriate events
@@ -2325,22 +2585,23 @@ void TDEHardwareDevices::addCoreSystemDevices() {
line.remove(0, line.find(":")+1);
line = line.stripWhiteSpace();
processorNumber = line.toInt();
- hwdevice = new TDEGenericDevice(TDEGenericDeviceType::CPU);
+ hwdevice = new TDECPUDevice(TDEGenericDeviceType::CPU);
hwdevice->setSystemPath(TQString("/sys/devices/system/cpu/cpu%1").arg(processorNumber));
m_deviceList.append(hwdevice);
- }
- if (line.startsWith("model name")) {
- line.remove(0, line.find(":")+1);
- line = line.stripWhiteSpace();
- hwdevice->setName(line);
+#if 0
+ // Set up CPU information monitor
+ // The only way CPU information can be changed is if something changes in the cpufreq node
+ // This may change in the future, but for now it is a fairly good assumption
+ m_cpuWatch->addDir(TQString("/sys/devices/system/cpu/cpu%1/cpufreq").arg(processorNumber));
+#endif
}
lines += line;
}
file.close();
}
- // FIXME
- // For each CPU, look for cpufreq and parse as much information as possible
+ // Populate CPU information
+ processModifiedCPUs();
}
TQString TDEHardwareDevices::findPCIDeviceName(TQString vendorid, TQString modelid, TQString subvendorid, TQString submodelid) {