public Core(Amd17Cpu cpu, int id) { _cpu = cpu; Threads = new List <CpuId>(); CoreId = id; _clock = new Sensor("Core #" + CoreId, cpu._sensorClock++, SensorType.Clock, cpu, cpu._settings); _multiplier = new Sensor("Core #" + CoreId, cpu._sensorMulti++, SensorType.Factor, cpu, cpu._settings); _power = new Sensor("Core #" + CoreId + " (SMU)", cpu._sensorPower++, SensorType.Power, cpu, cpu._settings); _vcore = new Sensor("Core #" + CoreId + " VID", cpu._sensorVoltage++, SensorType.Voltage, cpu, cpu._settings); cpu.ActivateSensor(_clock); cpu.ActivateSensor(_multiplier); cpu.ActivateSensor(_power); cpu.ActivateSensor(_vcore); }
public Processor(Hardware hw) { _hw = (Amd17Cpu)hw; Nodes = new List <NumaNode>(); _packagePower = new Sensor("Package Power", _hw._sensorPower++, SensorType.Power, _hw, _hw._settings); _coreTemperatureTctl = new Sensor("Core (Tctl)", _hw._sensorTemperatures++, SensorType.Temperature, _hw, _hw._settings); _coreTemperatureTdie = new Sensor("Core (Tdie)", _hw._sensorTemperatures++, SensorType.Temperature, _hw, _hw._settings); _coreVoltage = new Sensor("Core (SVI2 TFN)", _hw._sensorVoltage++, SensorType.Voltage, _hw, _hw._settings); _socVoltage = new Sensor("SoC (SVI2 TFN)", _hw._sensorVoltage++, SensorType.Voltage, _hw, _hw._settings); _hw.ActivateSensor(_packagePower); _hw.ActivateSensor(_coreTemperatureTctl); _hw.ActivateSensor(_coreTemperatureTdie); _hw.ActivateSensor(_coreVoltage); }
public Processor(Hardware hardware) { _cpu = (Amd17Cpu)hardware; _packagePower = new Sensor("Package Power", _cpu._sensorPower++, SensorType.Power, _cpu, _cpu._settings); _coreTemperatureTctl = new Sensor("Core (Tctl)", _cpu._sensorTemperatures++, SensorType.Temperature, _cpu, _cpu._settings); _coreTemperatureTdie = new Sensor("Core (Tdie)", _cpu._sensorTemperatures++, SensorType.Temperature, _cpu, _cpu._settings); _coreTemperatureTctlTdie = new Sensor("Core (Tctl/Tdie)", _cpu._sensorTemperatures++, SensorType.Temperature, _cpu, _cpu._settings); _ccdTemperatures = new Sensor[8]; // Hardcoded until there's a way to get max CCDs. _coreVoltage = new Sensor("Core (SVI2 TFN)", _cpu._sensorVoltage++, SensorType.Voltage, _cpu, _cpu._settings); _socVoltage = new Sensor("SoC (SVI2 TFN)", _cpu._sensorVoltage++, SensorType.Voltage, _cpu, _cpu._settings); _busClock = new Sensor("Bus Speed", _cpu._sensorClock++, SensorType.Clock, _cpu, _cpu._settings); _cpu.ActivateSensor(_packagePower); }
public Processor(Hardware hw) { _hw = (Amd17Cpu)hw; Nodes = new List <NumaNode>(); _packagePower = new Sensor("Package Power", _hw._sensorPower++, SensorType.Power, _hw, _hw._settings); _coreTemperatureTctl = new Sensor("Core (Tctl)", _hw._sensorTemperatures++, SensorType.Temperature, _hw, _hw._settings); _coreTemperatureTdie = new Sensor("Core (Tdie)", _hw._sensorTemperatures++, SensorType.Temperature, _hw, _hw._settings); _coreTemperatureTctlTdie = new Sensor("Core (Tctl/Tdie)", _hw._sensorTemperatures++, SensorType.Temperature, _hw, _hw._settings); _ccdTemperatures = new Sensor[8]; // Hardcoded until there's a way to get max CCDs. _coreVoltage = new Sensor("Core (SVI2 TFN)", _hw._sensorVoltage++, SensorType.Voltage, _hw, _hw._settings); _socVoltage = new Sensor("SoC (SVI2 TFN)", _hw._sensorVoltage++, SensorType.Voltage, _hw, _hw._settings); _hw.ActivateSensor(_packagePower); }
public void UpdateSensors() { NumaNode node = Nodes[0]; Core core = node?.Cores[0]; CpuId cpuId = core?.Threads[0]; if (cpuId == null) { return; } GroupAffinity previousAffinity = ThreadAffinity.Set(cpuId.Affinity); // MSRC001_0299 // TU [19:16] // ESU [12:8] -> Unit 15.3 micro Joule per increment // PU [3:0] Ring0.ReadMsr(MSR_PWR_UNIT, out uint _, out uint _); // MSRC001_029B // total_energy [31:0] DateTime sampleTime = DateTime.Now; Ring0.ReadMsr(MSR_PKG_ENERGY_STAT, out uint eax, out _); uint totalEnergy = eax; uint smuSvi0Tfn = 0; uint smuSvi0TelPlane0 = 0; uint smuSvi0TelPlane1 = 0; if (Ring0.WaitPciBusMutex(10)) { // THM_TCON_CUR_TMP // CUR_TEMP [31:21] Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_THM_TCON_CUR_TMP); Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint temperature); // SVI0_TFN_PLANE0 [0] // SVI0_TFN_PLANE1 [1] Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_SVI + 0x8); Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0Tfn); bool supportsPerCcdTemperatures = false; // TODO: find a better way because these will probably keep changing in the future. uint sviPlane0Offset; uint sviPlane1Offset; switch (cpuId.Model) { case 0x31: // Threadripper 3000. { sviPlane0Offset = F17H_M01H_SVI + 0x14; sviPlane1Offset = F17H_M01H_SVI + 0x10; supportsPerCcdTemperatures = true; break; } case 0x71: // Zen 2. case 0x21: // Zen 3. { sviPlane0Offset = F17H_M01H_SVI + 0x10; sviPlane1Offset = F17H_M01H_SVI + 0xC; supportsPerCcdTemperatures = true; break; } default: // Zen and Zen+. { sviPlane0Offset = F17H_M01H_SVI + 0xC; sviPlane1Offset = F17H_M01H_SVI + 0x10; break; } } // SVI0_PLANE0_VDDCOR [24:16] // SVI0_PLANE0_IDDCOR [7:0] Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, sviPlane0Offset); Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0TelPlane0); // SVI0_PLANE1_VDDCOR [24:16] // SVI0_PLANE1_IDDCOR [7:0] Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, sviPlane1Offset); Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0TelPlane1); ThreadAffinity.Set(previousAffinity); // power consumption // power.Value = (float) ((double)pu * 0.125); // esu = 15.3 micro Joule per increment if (_lastPwrTime.Ticks == 0) { _lastPwrTime = sampleTime; _lastPwrValue = totalEnergy; } // ticks diff TimeSpan time = sampleTime - _lastPwrTime; long pwr; if (_lastPwrValue <= totalEnergy) { pwr = totalEnergy - _lastPwrValue; } else { pwr = (0xffffffff - _lastPwrValue) + totalEnergy; } // update for next sample _lastPwrTime = sampleTime; _lastPwrValue = totalEnergy; double energy = 15.3e-6 * pwr; energy /= time.TotalSeconds; if (!double.IsNaN(energy)) { _packagePower.Value = (float)energy; } // current temp Bit [31:21] // If bit 19 of the Temperature Control register is set, there is an additional offset of 49 degrees C. bool tempOffsetFlag = (temperature & F17H_TEMP_OFFSET_FLAG) != 0; temperature = (temperature >> 21) * 125; float offset = 0.0f; // Offset table: https://github.com/torvalds/linux/blob/master/drivers/hwmon/k10temp.c#L78 if (string.IsNullOrWhiteSpace(cpuId.Name)) { offset = 0; } else if (cpuId.Name.Contains("1600X") || cpuId.Name.Contains("1700X") || cpuId.Name.Contains("1800X")) { offset = -20.0f; } else if (cpuId.Name.Contains("Threadripper 19") || cpuId.Name.Contains("Threadripper 29")) { offset = -27.0f; } else if (cpuId.Name.Contains("2700X")) { offset = -10.0f; } float t = temperature * 0.001f; if (tempOffsetFlag) { t += -49.0f; } if (offset < 0) { _coreTemperatureTctl.Value = t; _coreTemperatureTdie.Value = t + offset; _cpu.ActivateSensor(_coreTemperatureTctl); _cpu.ActivateSensor(_coreTemperatureTdie); } else { // Zen 2 doesn't have an offset so Tdie and Tctl are the same. _coreTemperatureTctlTdie.Value = t; _cpu.ActivateSensor(_coreTemperatureTctlTdie); } // Tested only on R5 3600 & Threadripper 3960X. if (supportsPerCcdTemperatures) { for (uint i = 0; i < _ccdTemperatures.Length; i++) { Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M70H_CCD1_TEMP + (i * 0x4)); Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint ccdRawTemp); ccdRawTemp &= 0xFFF; float ccdTemp = ((ccdRawTemp * 125) - 305000) * 0.001f; if (ccdRawTemp > 0 && ccdTemp < 125) // Zen 2 reports 95 degrees C max, but it might exceed that. { if (_ccdTemperatures[i] == null) { _cpu.ActivateSensor(_ccdTemperatures[i] = new Sensor($"CCD{i + 1} (Tdie)", _cpu._sensorTemperatures++, SensorType.Temperature, _cpu, _cpu._settings)); } _ccdTemperatures[i].Value = ccdTemp; } } Sensor[] activeCcds = _ccdTemperatures.Where(x => x != null).ToArray(); if (activeCcds.Length > 1) { // No need to get the max / average ccds temp if there is only one CCD. if (_ccdsMaxTemperature == null) { _cpu.ActivateSensor(_ccdsMaxTemperature = new Sensor("CCDs Max (Tdie)", _cpu._sensorTemperatures++, SensorType.Temperature, _cpu, _cpu._settings)); } if (_ccdsAverageTemperature == null) { _cpu.ActivateSensor(_ccdsAverageTemperature = new Sensor("CCDs Average (Tdie)", _cpu._sensorTemperatures++, SensorType.Temperature, _cpu, _cpu._settings)); } _ccdsMaxTemperature.Value = activeCcds.Max(x => x.Value); _ccdsAverageTemperature.Value = activeCcds.Average(x => x.Value); } } Ring0.ReleasePciBusMutex(); } // voltage const double vidStep = 0.00625; double vcc; uint svi0PlaneXVddCor; // Core (0x01). if ((smuSvi0Tfn & 0x01) == 0) { svi0PlaneXVddCor = (smuSvi0TelPlane0 >> 16) & 0xff; vcc = 1.550 - vidStep * svi0PlaneXVddCor; _coreVoltage.Value = (float)vcc; _cpu.ActivateSensor(_coreVoltage); } // SoC (0x02), not every Zen cpu has this voltage. if (cpuId.Model == 0x21 || cpuId.Model == 0x71 || cpuId.Model == 0x31 || (smuSvi0Tfn & 0x02) == 0) { svi0PlaneXVddCor = (smuSvi0TelPlane1 >> 16) & 0xff; vcc = 1.550 - vidStep * svi0PlaneXVddCor; _socVoltage.Value = (float)vcc; _cpu.ActivateSensor(_socVoltage); } double timeStampCounterMultiplier = GetTimeStampCounterMultiplier(); if (timeStampCounterMultiplier > 0) { _busClock.Value = (float)(_cpu.TimeStampCounterFrequency / timeStampCounterMultiplier); _cpu.ActivateSensor(_busClock); } }
public void UpdateSensors() { var node = Nodes[0]; Core core = node?.Cores[0]; CpuId cpu = core?.Threads[0]; if (cpu == null) { return; } ulong mask = Ring0.ThreadAffinitySet(1UL << cpu.Thread); // MSRC001_0299 // TU [19:16] // ESU [12:8] -> Unit 15.3 micro Joule per increment // PU [3:0] Ring0.ReadMsr(MSR_PWR_UNIT, out uint _, out uint _); // MSRC001_029B // total_energy [31:0] DateTime sampleTime = DateTime.Now; Ring0.ReadMsr(MSR_PKG_ENERGY_STAT, out uint eax, out _); uint totalEnergy = eax; // THM_TCON_CUR_TMP // CUR_TEMP [31:21] Ring0.WritePciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_THM_TCON_CUR_TMP); Ring0.ReadPciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint temperature); // SVI0_TFN_PLANE0 [0] // SVI0_TFN_PLANE1 [1] Ring0.WritePciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_SVI + 0x8); Ring0.ReadPciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint smuSvi0Tfn); // SVI0_PLANE0_VDDCOR [24:16] // SVI0_PLANE0_IDDCOR [7:0] Ring0.WritePciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_SVI + 0xc); Ring0.ReadPciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint smuSvi0TelPlane0); // SVI0_PLANE1_VDDCOR [24:16] // SVI0_PLANE1_IDDCOR [7:0] Ring0.WritePciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_SVI + 0x10); Ring0.ReadPciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint smuSvi0TelPlane1); Ring0.ThreadAffinitySet(mask); // power consumption // power.Value = (float) ((double)pu * 0.125); // esu = 15.3 micro Joule per increment if (_lastPwrTime.Ticks == 0) { _lastPwrTime = sampleTime; _lastPwrValue = totalEnergy; } // ticks diff TimeSpan time = sampleTime - _lastPwrTime; long pwr; if (_lastPwrValue <= totalEnergy) { pwr = totalEnergy - _lastPwrValue; } else { pwr = (0xffffffff - _lastPwrValue) + totalEnergy; } // update for next sample _lastPwrTime = sampleTime; _lastPwrValue = totalEnergy; double energy = 15.3e-6 * pwr; energy /= time.TotalSeconds; if (!double.IsNaN(energy)) { _packagePower.Value = (float)energy; } // current temp Bit [31:21] //If bit 19 of the Temperature Control register is set, there is an additional offset of 49 degrees C. bool tempOffsetFlag = (temperature & F17H_TEMP_OFFSET_FLAG) != 0; temperature = (temperature >> 21) * 125; float offset = 0.0f; if (string.IsNullOrWhiteSpace(cpu.Name)) { offset = 0; } else if (cpu.Name.Contains("1600X") || cpu.Name.Contains("1700X") || cpu.Name.Contains("1800X")) { offset = -20.0f; } else if (cpu.Name.Contains("1920X") || cpu.Name.Contains("1950X") || cpu.Name.Contains("1900X") || cpu.Name.Contains("2920") || cpu.Name.Contains("2950") || cpu.Name.Contains("2970") || cpu.Name.Contains("2990")) { offset = -27.0f; } else if (cpu.Name.Contains("2600X") || cpu.Name.Contains("2700X") || cpu.Name.Contains("2800X") || cpu.Name.Contains("1910") || cpu.Name.Contains("1920") || cpu.Name.Contains("1950")) { offset = -10.0f; } float t = temperature * 0.001f; if (tempOffsetFlag) { t += -49.0f; } _coreTemperatureTctl.Value = t; _coreTemperatureTdie.Value = t + offset; // voltage double vidStep = 0.00625; double vcc; uint svi0PlaneXVddCor; //Core if ((smuSvi0Tfn & 0x01) == 0) { svi0PlaneXVddCor = (smuSvi0TelPlane0 >> 16) & 0xff; vcc = 1.550 - vidStep * svi0PlaneXVddCor; _coreVoltage.Value = (float)vcc; } // SoC // not every zen cpu has this voltage if ((smuSvi0Tfn & 0x02) == 0) { svi0PlaneXVddCor = (smuSvi0TelPlane1 >> 16) & 0xff; vcc = 1.550 - vidStep * svi0PlaneXVddCor; _socVoltage.Value = (float)vcc; _hw.ActivateSensor(_socVoltage); } }