Branch: master

3c9d481f 2014-05-07 01:17:19 Francois Andriot
Greatly improve tdehwlib polling performance
This relates to Bug 1992
M tdecore/tdehw/tdehardwaredevices.cpp
M tdecore/tdehw/tdehardwaredevices.h
diff --git a/tdecore/tdehw/tdehardwaredevices.cpp b/tdecore/tdehw/tdehardwaredevices.cpp
index 30d06a7..092fba2 100644
--- a/tdecore/tdehw/tdehardwaredevices.cpp
+++ b/tdecore/tdehw/tdehardwaredevices.cpp
@@ -70,6 +70,24 @@
 // Compile-time configuration
 #include "config.h"
 
+// Profiling stuff
+//#define CPUPROFILING
+//#define STATELESSPROFILING
+
+#include <time.h>
+timespec diff(timespec start, timespec end)
+{
+	timespec temp;
+	if ((end.tv_nsec-start.tv_nsec)<0) {
+		temp.tv_sec = end.tv_sec-start.tv_sec-1;
+		temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
+	} else {
+		temp.tv_sec = end.tv_sec-start.tv_sec;
+		temp.tv_nsec = end.tv_nsec-start.tv_nsec;
+	}
+	return temp;
+}
+
 // BEGIN BLOCK
 // Copied from include/linux/genhd.h
 #define GENHD_FL_REMOVABLE                      1
@@ -199,6 +217,10 @@
 		m_deviceWatchTimer = new TQTimer(this);
 		connect( m_deviceWatchTimer, SIGNAL(timeout()), this, SLOT(processStatelessDevices()) );
 
+		// Special case for battery polling (longer delay, 5 seconds)
+		m_batteryWatchTimer = new TQTimer(this);
+		connect( m_batteryWatchTimer, SIGNAL(timeout()), this, SLOT(processBatteryDevices()) );
+
 		// Update internal device information
 		queryHardwareInformation();
 	}
@@ -207,6 +229,7 @@
 TDEHardwareDevices::~TDEHardwareDevices() {
 	// Stop device scanning
 	m_deviceWatchTimer->stop();
+	m_batteryWatchTimer->stop();
 
 // [FIXME 0.01]
 #if 0
@@ -243,11 +266,26 @@
 		if (nodezerocpufreq.exists()) {
 			m_cpuWatchTimer->start( 500, FALSE ); // 0.5 second repeating timer
 		}
+		m_batteryWatchTimer->stop(); // Battery devices are included in stateless devices
 		m_deviceWatchTimer->start( 1000, FALSE ); // 1 second repeating timer
 	}
 	else {
 		m_cpuWatchTimer->stop();
 		m_deviceWatchTimer->stop();
+	}
+}
+
+void TDEHardwareDevices::setBatteryUpdatesEnabled(bool enable) {
+	if (enable) {
+		TQDir nodezerocpufreq("/sys/devices/system/cpu/cpu0/cpufreq");
+		if (nodezerocpufreq.exists()) {
+			m_cpuWatchTimer->start( 500, FALSE ); // 0.5 second repeating timer
+		}
+		m_batteryWatchTimer->start( 5000, FALSE ); // 5 second repeating timer
+	}
+	else {
+		m_cpuWatchTimer->stop();
+		m_batteryWatchTimer->stop();
 	}
 }
 
@@ -270,6 +308,7 @@
 		syspath += "/";
 	}
 	TDEGenericDevice *hwdevice;
+
 	// We can't use m_deviceList directly as m_deviceList can only have one iterator active against it at any given time
 	TDEGenericHardwareList devList = listAllPhysicalDevices();
 	for ( hwdevice = devList.first(); hwdevice; hwdevice = devList.next() ) {
@@ -280,6 +319,30 @@
 
 	return 0;
 }
+
+TDECPUDevice* TDEHardwareDevices::findCPUBySystemPath(TQString syspath, bool inCache=true) {
+	TDECPUDevice* cdevice;
+	
+	// Look for the device in the cache first
+	if(inCache && !m_cpuByPathCache.isEmpty()) {
+		cdevice = m_cpuByPathCache.find(syspath);
+		if(cdevice) {
+			return cdevice;
+		}
+	}
+
+	// If the CPU was not found in cache, we need to parse the entire device list to get it.
+	cdevice = dynamic_cast<TDECPUDevice*>(findBySystemPath(syspath));
+	if(cdevice) {
+		if(inCache) {
+			m_cpuByPathCache.insert(syspath, cdevice); // Add the device to the cache
+		}
+		return cdevice;
+	}
+	
+	return 0;
+}
+
 
 TDEGenericDevice* TDEHardwareDevices::findByUniqueID(TQString uid) {
 	TDEGenericDevice *hwdevice;
@@ -410,16 +473,28 @@
 	// Detect what changed between the old cpu information and the new information,
 	// and emit appropriate events
 
+#ifdef CPUPROFILING
+	timespec time1, time2, time3;
+	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
+	time3 = time1;
+	printf("TDEHardwareDevices::processModifiedCPUs() : begin at '%u'\n", time1.tv_nsec);
+#endif
+
 	// 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());
-		}
+		// Using read() instead of readLine() inside a loop is 4 times faster !
+		m_cpuInfo = TQStringList::split('\n', stream.read(), true);
 		cpufile.close();
 	}
+
+#ifdef CPUPROFILING
+	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
+	printf("TDEHardwareDevices::processModifiedCPUs() : checkpoint1 at %u [%u]\n", time2.tv_nsec, diff(time1,time2).tv_nsec);
+	time1 = time2;
+#endif
 
 	// Ensure "processor" is the first entry in each block and determine which cpuinfo type is in use
 	bool cpuinfo_format_x86 = true;
@@ -431,38 +506,42 @@
 	TQStringList::Iterator blockBegin = m_cpuInfo.begin();
 	for (TQStringList::Iterator cpuit1 = m_cpuInfo.begin(); cpuit1 != m_cpuInfo.end(); ++cpuit1) {
 		curline1 = *cpuit1;
-		curline1 = curline1.stripWhiteSpace();
 		if (!(*blockBegin).startsWith("processor")) {
 			bool found = false;
 			TQStringList::Iterator cpuit2;
 			for (cpuit2 = blockBegin; cpuit2 != m_cpuInfo.end(); ++cpuit2) {
 				curline2 = *cpuit2;
-				curline2 = curline2.stripWhiteSpace();
 				if (curline2.startsWith("processor")) {
 					found = true;
 					break;
 				}
-				else if (curline2 == "") {
+				else if (curline2 == NULL || curline2 == "") {
 					break;
 				}
 			}
 			if (found) {
 				m_cpuInfo.insert(blockBegin, (*cpuit2));
 			}
-			else {
+			else if(blockNumber == 0) {
 				m_cpuInfo.insert(blockBegin, "processor : 0");
 			}
 		}
-		if (curline1 == "") {
+		if (curline1 == NULL || curline1 == "") {
 			blockNumber++;
 			blockBegin = cpuit1;
 			blockBegin++;
 		}
-		if (curline1.startsWith("Processor")) {
+		else if (curline1.startsWith("Processor")) {
 			cpuinfo_format_x86 = false;
 			cpuinfo_format_arm = true;
 		}
 	}
+
+#ifdef CPUPROFILING
+	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
+	printf("TDEHardwareDevices::processModifiedCPUs() : checkpoint2 at %u [%u]\n", time2.tv_nsec, diff(time1,time2).tv_nsec);
+	time1 = time2;
+#endif
 
 	// Parse CPU information table
 	TDECPUDevice *cdevice;
@@ -482,44 +561,45 @@
 		for (cpuit = m_cpuInfo.begin(); cpuit != m_cpuInfo.end(); ++cpuit) {
 			curline = *cpuit;
 			if (curline.startsWith("processor")) {
-				curline.remove(0, curline.find(":")+1);
-				curline = curline.stripWhiteSpace();
+				curline.remove(0, curline.find(":")+2);
 				processorNumber = curline.toInt();
-				if (!cdevice) cdevice = dynamic_cast<TDECPUDevice*>(findBySystemPath(TQString("/sys/devices/system/cpu/cpu%1").arg(processorNumber)));
+				if (!cdevice) {
+					cdevice = dynamic_cast<TDECPUDevice*>(findCPUBySystemPath(TQString("/sys/devices/system/cpu/cpu%1").arg(processorNumber)));
+				}
 				if (cdevice) {
-					if (cdevice->coreNumber() != processorNumber) modified = true;
-					cdevice->internalSetCoreNumber(processorNumber);
+					if (cdevice->coreNumber() != processorNumber) {
+						modified = true;
+						cdevice->internalSetCoreNumber(processorNumber);
+					}
 				}
 			}
-			if (curline.startsWith("model name")) {
-				curline.remove(0, curline.find(":")+1);
-				curline = curline.stripWhiteSpace();
-				if (cdevice) {
-					if (cdevice->name() != curline) modified = true;
+			else if (cdevice && curline.startsWith("model name")) {
+				curline.remove(0, curline.find(":")+2);
+				if (cdevice->name() != curline) {
+					modified = true;
 					cdevice->internalSetName(curline);
 				}
 			}
-			if (curline.startsWith("cpu MHz")) {
-				curline.remove(0, curline.find(":")+1);
-				curline = curline.stripWhiteSpace();
-				if (cdevice) {
-					if (cdevice->frequency() != curline.toDouble()) modified = true;
+			else if (cdevice && curline.startsWith("cpu MHz")) {
+				curline.remove(0, curline.find(":")+2);
+				if (cdevice->frequency() != curline.toDouble()) {
+					modified = true;
 					cdevice->internalSetFrequency(curline.toDouble());
-					have_frequency = true;
 				}
+				have_frequency = true;
 			}
-			if (curline.startsWith("vendor_id")) {
-				curline.remove(0, curline.find(":")+1);
-				curline = curline.stripWhiteSpace();
-				if (cdevice) {
-					if (cdevice->vendorName() != curline) modified = true;
+			else if (cdevice && curline.startsWith("vendor_id")) {
+				curline.remove(0, curline.find(":")+2);
+				if (cdevice->vendorName() != curline) {
 ** Diff limit reached (max: 250 lines) **