Fixed Issue 387. The new implementation does not try to start a ring 0 driver that already exists, but could not be opened. It tries to delete the driver and install it new. The driver is now stored temporarily in the application folder. The driver is not correctly removed on system shutdown.
3 This Source Code Form is subject to the terms of the Mozilla Public
4 License, v. 2.0. If a copy of the MPL was not distributed with this
5 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 Copyright (C) 2010-2011 Michael Möller <mmoeller@openhardwaremonitor.org>
12 using System.Collections.Generic;
13 using System.Diagnostics;
14 using System.Globalization;
15 using System.Runtime.InteropServices;
17 using System.Threading;
19 namespace OpenHardwareMonitor.Hardware.CPU {
20 internal class GenericCPU : Hardware {
22 protected readonly CPUID[][] cpuid;
24 protected readonly uint family;
25 protected readonly uint model;
26 protected readonly uint stepping;
28 protected readonly int processorIndex;
29 protected readonly int coreCount;
31 private readonly bool hasModelSpecificRegisters;
33 private readonly bool hasTimeStampCounter;
34 private readonly bool isInvariantTimeStampCounter;
35 private readonly double estimatedTimeStampCounterFrequency;
36 private readonly double estimatedTimeStampCounterFrequencyError;
38 private ulong lastTimeStampCount;
39 private long lastTime;
40 private double timeStampCounterFrequency;
43 private readonly Vendor vendor;
45 private readonly CPULoad cpuLoad;
46 private readonly Sensor totalLoad;
47 private readonly Sensor[] coreLoads;
49 protected string CoreString(int i) {
53 return "CPU Core #" + (i + 1);
56 public GenericCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
57 : base(cpuid[0][0].Name, CreateIdentifier(cpuid[0][0].Vendor,
58 processorIndex), settings)
62 this.vendor = cpuid[0][0].Vendor;
64 this.family = cpuid[0][0].Family;
65 this.model = cpuid[0][0].Model;
66 this.stepping = cpuid[0][0].Stepping;
68 this.processorIndex = processorIndex;
69 this.coreCount = cpuid.Length;
71 // check if processor has MSRs
72 if (cpuid[0][0].Data.GetLength(0) > 1
73 && (cpuid[0][0].Data[1, 3] & 0x20) != 0)
74 hasModelSpecificRegisters = true;
76 hasModelSpecificRegisters = false;
78 // check if processor has a TSC
79 if (cpuid[0][0].Data.GetLength(0) > 1
80 && (cpuid[0][0].Data[1, 3] & 0x10) != 0)
81 hasTimeStampCounter = true;
83 hasTimeStampCounter = false;
85 // check if processor supports an invariant TSC
86 if (cpuid[0][0].ExtData.GetLength(0) > 7
87 && (cpuid[0][0].ExtData[7, 3] & 0x100) != 0)
88 isInvariantTimeStampCounter = true;
90 isInvariantTimeStampCounter = false;
93 totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this, settings);
96 coreLoads = new Sensor[coreCount];
97 for (int i = 0; i < coreLoads.Length; i++)
98 coreLoads[i] = new Sensor(CoreString(i), i + 1,
99 SensorType.Load, this, settings);
100 cpuLoad = new CPULoad(cpuid);
101 if (cpuLoad.IsAvailable) {
102 foreach (Sensor sensor in coreLoads)
103 ActivateSensor(sensor);
104 if (totalLoad != null)
105 ActivateSensor(totalLoad);
108 if (hasTimeStampCounter) {
109 ulong mask = ThreadAffinity.Set(1UL << cpuid[0][0].Thread);
111 EstimateTimeStampCounterFrequency(
112 out estimatedTimeStampCounterFrequency,
113 out estimatedTimeStampCounterFrequencyError);
115 ThreadAffinity.Set(mask);
117 estimatedTimeStampCounterFrequency = 0;
120 timeStampCounterFrequency = estimatedTimeStampCounterFrequency;
123 private static Identifier CreateIdentifier(Vendor vendor,
128 case Vendor.AMD: s = "amdcpu"; break;
129 case Vendor.Intel: s = "intelcpu"; break;
130 default: s = "genericcpu"; break;
132 return new Identifier(s,
133 processorIndex.ToString(CultureInfo.InvariantCulture));
136 private void EstimateTimeStampCounterFrequency(out double frequency,
141 // preload the function
142 EstimateTimeStampCounterFrequency(0, out f, out e);
143 EstimateTimeStampCounterFrequency(0, out f, out e);
145 // estimate the frequency
146 error = double.MaxValue;
148 for (int i = 0; i < 5; i++) {
149 EstimateTimeStampCounterFrequency(0.025, out f, out e);
160 private void EstimateTimeStampCounterFrequency(double timeWindow,
161 out double frequency, out double error)
163 long ticks = (long)(timeWindow * Stopwatch.Frequency);
164 ulong countBegin, countEnd;
166 long timeBegin = Stopwatch.GetTimestamp() +
167 (long)Math.Ceiling(0.001 * ticks);
168 long timeEnd = timeBegin + ticks;
170 while (Stopwatch.GetTimestamp() < timeBegin) { }
171 countBegin = Opcode.Rdtsc();
172 long afterBegin = Stopwatch.GetTimestamp();
174 while (Stopwatch.GetTimestamp() < timeEnd) { }
175 countEnd = Opcode.Rdtsc();
176 long afterEnd = Stopwatch.GetTimestamp();
178 double delta = (timeEnd - timeBegin);
180 (((double)(countEnd - countBegin)) * Stopwatch.Frequency) / delta;
182 double beginError = (afterBegin - timeBegin) / delta;
183 double endError = (afterEnd - timeEnd) / delta;
184 error = beginError + endError;
188 private static void AppendMSRData(StringBuilder r, uint msr, int thread) {
190 if (Ring0.RdmsrTx(msr, out eax, out edx, 1UL << thread)) {
192 r.Append((msr).ToString("X8", CultureInfo.InvariantCulture));
194 r.Append((edx).ToString("X8", CultureInfo.InvariantCulture));
196 r.Append((eax).ToString("X8", CultureInfo.InvariantCulture));
201 protected virtual uint[] GetMSRs() {
205 public override string GetReport() {
206 StringBuilder r = new StringBuilder();
209 case Vendor.AMD: r.AppendLine("AMD CPU"); break;
210 case Vendor.Intel: r.AppendLine("Intel CPU"); break;
211 default: r.AppendLine("Generic CPU"); break;
215 r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
216 r.AppendFormat("Number of Cores: {0}{1}", coreCount,
217 Environment.NewLine);
218 r.AppendFormat("Threads per Core: {0}{1}", cpuid[0].Length,
219 Environment.NewLine);
220 r.AppendLine(string.Format(CultureInfo.InvariantCulture,
221 "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
222 r.AppendLine("Time Stamp Counter: " + (hasTimeStampCounter ? (
223 isInvariantTimeStampCounter ? "Invariant" : "Not Invariant") : "None"));
224 r.AppendLine(string.Format(CultureInfo.InvariantCulture,
225 "Estimated Time Stamp Counter Frequency: {0} MHz",
226 Math.Round(estimatedTimeStampCounterFrequency * 100) * 0.01));
227 r.AppendLine(string.Format(CultureInfo.InvariantCulture,
228 "Estimated Time Stamp Counter Frequency Error: {0} Mhz",
229 Math.Round(estimatedTimeStampCounterFrequency *
230 estimatedTimeStampCounterFrequencyError * 1e5) * 1e-5));
231 r.AppendLine(string.Format(CultureInfo.InvariantCulture,
232 "Time Stamp Counter Frequency: {0} MHz",
233 Math.Round(timeStampCounterFrequency * 100) * 0.01));
236 uint[] msrArray = GetMSRs();
237 if (msrArray != null && msrArray.Length > 0) {
238 for (int i = 0; i < cpuid.Length; i++) {
239 r.AppendLine("MSR Core #" + (i + 1));
241 r.AppendLine(" MSR EDX EAX");
242 foreach (uint msr in msrArray)
243 AppendMSRData(r, msr, cpuid[i][0].Thread);
251 public override HardwareType HardwareType {
252 get { return HardwareType.CPU; }
255 public bool HasModelSpecificRegisters {
256 get { return hasModelSpecificRegisters; }
259 public bool HasTimeStampCounter {
260 get { return hasTimeStampCounter; }
263 public double TimeStampCounterFrequency {
264 get { return timeStampCounterFrequency; }
267 public override void Update() {
268 if (hasTimeStampCounter && isInvariantTimeStampCounter) {
270 // make sure always the same thread is used
271 ulong mask = ThreadAffinity.Set(1UL << cpuid[0][0].Thread);
273 // read time before and after getting the TSC to estimate the error
274 long firstTime = Stopwatch.GetTimestamp();
275 ulong timeStampCount = Opcode.Rdtsc();
276 long time = Stopwatch.GetTimestamp();
278 // restore the thread affinity mask
279 ThreadAffinity.Set(mask);
281 double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
282 double error = ((double)(time - firstTime)) / Stopwatch.Frequency;
284 // only use data if they are measured accuarte enough (max 0.1ms delay)
285 if (error < 0.0001) {
287 // ignore the first reading because there are no initial values
288 // ignore readings with too large or too small time window
289 if (lastTime != 0 && delta > 0.5 && delta < 2) {
291 // update the TSC frequency with the new value
292 timeStampCounterFrequency =
293 (timeStampCount - lastTimeStampCount) / (1e6 * delta);
296 lastTimeStampCount = timeStampCount;
301 if (cpuLoad.IsAvailable) {
303 for (int i = 0; i < coreLoads.Length; i++)
304 coreLoads[i].Value = cpuLoad.GetCoreLoad(i);
305 if (totalLoad != null)
306 totalLoad.Value = cpuLoad.GetTotalLoad();