James Eder : ntdll: Add more complete implementation of NtPowerInformation.

Alexandre Julliard julliard at winehq.org
Fri Sep 14 10:54:21 CDT 2012


Module: wine
Branch: master
Commit: 2a71712b51a7c17645f98dd6fdd377ecea7f7026
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=2a71712b51a7c17645f98dd6fdd377ecea7f7026

Author: James Eder <jimportal at gmail.com>
Date:   Thu Sep 13 15:12:15 2012 -0600

ntdll: Add more complete implementation of NtPowerInformation.

---

 dlls/ntdll/nt.c |  169 +++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 139 insertions(+), 30 deletions(-)

diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index ca05203..878c58b 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -810,7 +810,6 @@ NTSTATUS WINAPI NtSetIntervalProfile(
 }
 
 static  SYSTEM_CPU_INFORMATION cached_sci;
-static  ULONGLONG cpuHz = 1000000000; /* default to a 1GHz */
 
 #define AUTH	0x68747541	/* "Auth" */
 #define ENTI	0x69746e65	/* "enti" */
@@ -901,7 +900,7 @@ static inline void get_cpuinfo(SYSTEM_CPU_INFORMATION* info)
  *		fill_cpu_info
  *
  * inits a couple of places with CPU related information:
- * - cached_sci & cpuHZ in this file
+ * - cached_sci in this file
  * - Peb->NumberOfProcessors
  * - SharedUserData->ProcessFeatures[] array
  */
@@ -1019,16 +1018,6 @@ void fill_cpu_info(void)
                     cached_sci.Revision = cached_sci.Revision | x;
                 continue;
             }
-            if (!strcasecmp(line, "cpu MHz"))
-            {
-                double cmz;
-                if (sscanf( value, "%lf", &cmz ) == 1)
-                {
-                    /* SYSTEMINFO doesn't have a slot for cpu speed, so store in a global */
-                    cpuHz = cmz * 1000 * 1000;
-                }
-                continue;
-            }
             if (!strcasecmp(line, "fdiv_bug"))
             {
                 if (!strncasecmp(value, "yes",3))
@@ -1190,10 +1179,6 @@ void fill_cpu_info(void)
         ret = sysctlbyname("hw.ncpu", &num, &len, NULL, 0);
         if (!ret)
             NtCurrentTeb()->Peb->NumberOfProcessors = num;
-
-        len = sizeof(num);
-        if (!sysctlbyname("hw.clockrate", &num, &len, NULL, 0))
-            cpuHz = num * 1000 * 1000;
     }
 #elif defined(__sun)
     {
@@ -1219,7 +1204,6 @@ void fill_cpu_info(void)
 #elif defined (__APPLE__)
     {
         size_t valSize;
-        unsigned long long longVal;
         int value;
         int cputype;
         char buffer[1024];
@@ -1300,9 +1284,6 @@ void fill_cpu_info(void)
             default: break;
             } /* switch (cputype) */
         }
-        valSize = sizeof(longVal);
-        if (!sysctlbyname("hw.cpufrequency", &longVal, &valSize, NULL, 0))
-            cpuHz = longVal;
     }
 #else
     FIXME("not yet supported on this system\n");
@@ -2261,7 +2242,35 @@ NTSTATUS WINAPI NtInitiatePowerAction(
 		SystemAction,MinSystemState,Flags,Asynchronous);
         return STATUS_NOT_IMPLEMENTED;
 }
-	
+
+#ifdef linux
+/* Fallback using /proc/cpuinfo for Linux systems without cpufreq. For
+ * most distributions on recent enough hardware, this is only likely to
+ * happen while running in virtualized environments such as QEMU. */
+static ULONG mhz_from_cpuinfo(void)
+{
+    char line[512];
+    char *s, *value;
+    double cmz = 0;
+    FILE* f = fopen("/proc/cpuinfo", "r");
+    if(f) {
+        while (fgets(line, sizeof(line), f) != NULL) {
+            if (!(value = strchr(line,':')))
+                continue;
+            s = value - 1;
+            while ((s >= line) && isspace(*s)) s--;
+            *(s + 1) = '\0';
+            value++;
+            if (!strcasecmp(line, "cpu MHz")) {
+                sscanf(value, " %lf", &cmz);
+                break;
+            }
+        }
+        fclose(f);
+    }
+    return cmz;
+}
+#endif
 
 /******************************************************************************
  *  NtPowerInformation				[NTDLL.@]
@@ -2326,24 +2335,124 @@ NTSTATUS WINAPI NtPowerInformation(
 			return STATUS_SUCCESS;
 		}
 		case ProcessorInformation: {
+			const int cannedMHz = 1000; /* We fake a 1GHz processor if we can't conjure up real values */
 			PROCESSOR_POWER_INFORMATION* cpu_power = lpOutputBuffer;
-			int i;
-
-			WARN("semi-stub: ProcessorInformation\n");
+			int i, out_cpus;
 
 			if ((lpOutputBuffer == NULL) || (nOutputBufferSize == 0))
 				return STATUS_INVALID_PARAMETER;
-			if ((nOutputBufferSize / sizeof(PROCESSOR_POWER_INFORMATION)) < NtCurrentTeb()->Peb->NumberOfProcessors)
+			out_cpus = NtCurrentTeb()->Peb->NumberOfProcessors;
+			if ((nOutputBufferSize / sizeof(PROCESSOR_POWER_INFORMATION)) < out_cpus)
 				return STATUS_BUFFER_TOO_SMALL;
-
-			for(i = 0; i < NtCurrentTeb()->Peb->NumberOfProcessors; i++) {
+#if defined(linux)
+			{
+				char filename[128];
+				FILE* f;
+
+				for(i = 0; i < out_cpus; i++) {
+					sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i);
+					f = fopen(filename, "r");
+					if (f && (fscanf(f, "%d", &cpu_power[i].CurrentMhz) == 1)) {
+						cpu_power[i].CurrentMhz /= 1000;
+						fclose(f);
+					}
+					else {
+						if(i == 0) {
+							cpu_power[0].CurrentMhz = mhz_from_cpuinfo();
+							if(cpu_power[0].CurrentMhz == 0)
+								cpu_power[0].CurrentMhz = cannedMHz;
+						}
+						else
+							cpu_power[i].CurrentMhz = cpu_power[0].CurrentMhz;
+						if(f) fclose(f);
+					}
+
+					sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i);
+					f = fopen(filename, "r");
+					if (f && (fscanf(f, "%d", &cpu_power[i].MaxMhz) == 1)) {
+						cpu_power[i].MaxMhz /= 1000;
+						fclose(f);
+					}
+					else {
+						cpu_power[i].MaxMhz = cpu_power[i].CurrentMhz;
+						if(f) fclose(f);
+					}
+
+					sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", i);
+					f = fopen(filename, "r");
+					if(f && (fscanf(f, "%d", &cpu_power[i].MhzLimit) == 1)) {
+						cpu_power[i].MhzLimit /= 1000;
+						fclose(f);
+					}
+					else
+					{
+						cpu_power[i].MhzLimit = cpu_power[i].MaxMhz;
+						if(f) fclose(f);
+					}
+
+					cpu_power[i].Number = i;
+					cpu_power[i].MaxIdleState = 0;     /* FIXME */
+					cpu_power[i].CurrentIdleState = 0; /* FIXME */
+				}
+			}
+#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
+			{
+				int num;
+				size_t valSize = sizeof(num);
+				if (sysctlbyname("hw.clockrate", &num, &valSize, NULL, 0))
+					num = cannedMHz;
+				for(i = 0; i < out_cpus; i++) {
+					cpu_power[i].CurrentMhz = num;
+					cpu_power[i].MaxMhz = num;
+					cpu_power[i].MhzLimit = num;
+					cpu_power[i].Number = i;
+					cpu_power[i].MaxIdleState = 0;     /* FIXME */
+					cpu_power[i].CurrentIdleState = 0; /* FIXME */
+				}
+			}
+#elif defined (__APPLE__)
+			{
+				size_t valSize;
+				unsigned long long currentMhz;
+				unsigned long long maxMhz;
+
+				valSize = sizeof(currentMhz);
+				if (!sysctlbyname("hw.cpufrequency", &currentMhz, &valSize, NULL, 0))
+					currentMhz /= 1000000;
+				else
+					currentMhz = cannedMHz;
+
+				valSize = sizeof(maxMhz);
+				if (!sysctlbyname("hw.cpufrequency_max", &maxMhz, &valSize, NULL, 0))
+					maxMhz /= 1000000;
+				else
+					maxMhz = currentMhz;
+
+				for(i = 0; i < out_cpus; i++) {
+					cpu_power[i].CurrentMhz = currentMhz;
+					cpu_power[i].MaxMhz = maxMhz;
+					cpu_power[i].MhzLimit = maxMhz;
+					cpu_power[i].Number = i;
+					cpu_power[i].MaxIdleState = 0;     /* FIXME */
+					cpu_power[i].CurrentIdleState = 0; /* FIXME */
+				}
+			}
+#else
+			for(i = 0; i < out_cpus; i++) {
+				cpu_power[i].CurrentMhz = cannedMHz;
+				cpu_power[i].MaxMhz = cannedMHz;
+				cpu_power[i].MhzLimit = cannedMHz;
 				cpu_power[i].Number = i;
-				cpu_power[i].MaxMhz = cpuHz / 1000000;
-				cpu_power[i].CurrentMhz = cpuHz / 1000000;
-				cpu_power[i].MhzLimit = cpuHz / 1000000;
 				cpu_power[i].MaxIdleState = 0; /* FIXME */
 				cpu_power[i].CurrentIdleState = 0; /* FIXME */
 			}
+			WARN("Unable to detect CPU MHz for this platform. Reporting %d MHz.\n", cannedMHz);
+#endif
+			for(i = 0; i < out_cpus; i++) {
+				TRACE("cpu_power[%d] = %u %u %u %u %u %u\n", i, cpu_power[i].Number,
+					  cpu_power[i].MaxMhz, cpu_power[i].CurrentMhz, cpu_power[i].MhzLimit,
+					  cpu_power[i].MaxIdleState, cpu_power[i].CurrentIdleState);
+			}
 			return STATUS_SUCCESS;
 		}
 		default:




More information about the wine-cvs mailing list