Exemple #1
0
        private static CpuId[][] GroupThreadsByCore(IEnumerable <CpuId> threads)
        {
            SortedDictionary <uint, List <CpuId> > cores = new SortedDictionary <uint, List <CpuId> >();

            foreach (CpuId thread in threads)
            {
                cores.TryGetValue(thread.CoreId, out List <CpuId> coreList);
                if (coreList == null)
                {
                    coreList = new List <CpuId>();
                    cores.Add(thread.CoreId, coreList);
                }

                coreList.Add(thread);
            }

            CpuId[][] coreThreads = new CpuId[cores.Count][];
            int       index       = 0;

            foreach (List <CpuId> list in cores.Values)
            {
                coreThreads[index] = list.ToArray();
                index++;
            }

            return(coreThreads);
        }
        private static CpuId[][] GetProcessorThreads()
        {
            List <CpuId> threads = new List <CpuId>();

            for (int i = 0; i < ThreadAffinity.ProcessorGroupCount; i++)
            {
                for (int j = 0; j < 64; j++)
                {
                    try
                    {
                        if (!ThreadAffinity.IsValid(GroupAffinity.Single((ushort)i, j)))
                        {
                            continue;
                        }


                        var cpuid = CpuId.Get(i, j);
                        if (cpuid != null)
                        {
                            threads.Add(cpuid);
                        }
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        // All cores found.
                        break;
                    }
                }
            }


            SortedDictionary <uint, List <CpuId> > processors = new SortedDictionary <uint, List <CpuId> >();

            foreach (CpuId thread in threads)
            {
                processors.TryGetValue(thread.ProcessorId, out List <CpuId> list);
                if (list == null)
                {
                    list = new List <CpuId>();
                    processors.Add(thread.ProcessorId, list);
                }

                list.Add(thread);
            }

            CpuId[][] processorThreads = new CpuId[processors.Count][];
            int       index            = 0;

            foreach (List <CpuId> list in processors.Values)
            {
                processorThreads[index] = list.ToArray();
                index++;
            }

            return(processorThreads);
        }
Exemple #3
0
        public Amd17Cpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings)
        {
            _sensorTypeIndex = new Dictionary <SensorType, int>();
            foreach (SensorType type in Enum.GetValues(typeof(SensorType)))
            {
                _sensorTypeIndex.Add(type, 0);
            }

            _sensorTypeIndex[SensorType.Load] = _active.Count(x => x.SensorType == SensorType.Load);

            _smu = new RyzenSMU(_family, _model, _packageType);

            // Add all numa nodes.
            // Register ..1E_2, [10:8] + 1
            _processor = new Processor(this);

            // Add all numa nodes.
            int coreId     = 0;
            int lastCoreId = -1; // Invalid id.

            // Ryzen 3000's skip some core ids.
            // So start at 1 and count upwards when the read core changes.
            foreach (CpuId[] cpu in cpuId.OrderBy(x => x[0].ExtData[0x1e, 1] & 0xFF))
            {
                CpuId thread = cpu[0];

                // CPUID_Fn8000001E_EBX, Register ..1E_1, [7:0]
                // threads per core =  CPUID_Fn8000001E_EBX[15:8] + 1
                // CoreId: core ID =  CPUID_Fn8000001E_EBX[7:0]
                int coreIdRead = (int)(thread.ExtData[0x1e, 1] & 0xff);

                // CPUID_Fn8000001E_ECX, Node Identifiers, Register ..1E_2
                // NodesPerProcessor =  CPUID_Fn8000001E_ECX[10:8]
                // nodeID =  CPUID_Fn8000001E_ECX[7:0]
                int nodeId = (int)(thread.ExtData[0x1e, 2] & 0xff);

                if (coreIdRead != lastCoreId)
                {
                    coreId++;
                }

                lastCoreId = coreIdRead;

                _processor.AppendThread(thread, nodeId, coreId);
            }

            Update();
        }
Exemple #4
0
        private static CpuId[][] GetProcessorThreads()
        {
            List <CpuId> threads = new List <CpuId>();

            for (int i = 0; i < 64; i++)
            {
                try
                {
                    threads.Add(new CpuId(i));
                }
                catch (ArgumentOutOfRangeException)
                {
                    // All cores found.
                    break;
                }
            }

            SortedDictionary <uint, List <CpuId> > processors = new SortedDictionary <uint, List <CpuId> >();

            foreach (CpuId thread in threads)
            {
                processors.TryGetValue(thread.ProcessorId, out List <CpuId> list);
                if (list == null)
                {
                    list = new List <CpuId>();
                    processors.Add(thread.ProcessorId, list);
                }

                list.Add(thread);
            }

            CpuId[][] processorThreads = new CpuId[processors.Count][];
            int       index            = 0;

            foreach (List <CpuId> list in processors.Values)
            {
                processorThreads[index] = list.ToArray();
                index++;
            }

            return(processorThreads);
        }
Exemple #5
0
        public Amd17Cpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings)
        {
            // add all numa nodes
            // Register ..1E_2, [10:8] + 1
            _processor = new Processor(this);

            // add all numa nodes
            const int initialCoreId = 1_000_000_000;

            int coreId     = 1;
            int lastCoreId = initialCoreId;

            // Ryzen 3000's skip some core ids.
            // So start at 1 and count upwards when the read core changes.
            foreach (CpuId[] cpu in cpuId.OrderBy(x => x[0].ExtData[0x1e, 1] & 0xFF))
            {
                CpuId thread = cpu[0];

                // coreID
                // Register ..1E_1, [7:0]
                int coreIdRead = (int)(thread.ExtData[0x1e, 1] & 0xff);

                // nodeID
                // Register ..1E_2, [7:0]
                int nodeId = (int)(thread.ExtData[0x1e, 2] & 0xff);

                _processor.AppendThread(thread, nodeId, coreId);

                if (lastCoreId != initialCoreId && coreIdRead != lastCoreId)
                {
                    coreId++;
                }

                lastCoreId = coreIdRead;
            }

            Update();
        }
Exemple #6
0
            public void AppendThread(CpuId thread, int coreId)
            {
                Core core = null;

                foreach (Core c in Cores)
                {
                    if (c.CoreId == coreId)
                    {
                        core = c;
                    }
                }

                if (core == null)
                {
                    core = new Core(_cpu, coreId);
                    Cores.Add(core);
                }

                if (thread != null)
                {
                    core.Threads.Add(thread);
                }
            }
Exemple #7
0
        public Amd17Cpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings)
        {
            // Add all numa nodes.
            // Register ..1E_2, [10:8] + 1
            _processor = new Processor(this);

            // Add all numa nodes.
            int coreId     = 0;
            int lastCoreId = -1; // Invalid id.

            // Ryzen 3000's skip some core ids.
            // So start at 1 and count upwards when the read core changes.
            foreach (CpuId[] cpu in cpuId.OrderBy(x => x[0].ExtData[0x1e, 1] & 0xFF))
            {
                CpuId thread = cpu[0];

                // CPUID_Fn8000001E_EBX, Register ..1E_1, [7:0]
                // threads per core =  CPUID_Fn8000001E_EBX[15:8] + 1
                // CoreId: core ID =  CPUID_Fn8000001E_EBX[7:0]
                int coreIdRead = (int)(thread.ExtData[0x1e, 1] & 0xff);

                // CPUID_Fn8000001E_ECX, Node Identifiers, Register ..1E_2
                // NodesPerProcessor =  CPUID_Fn8000001E_ECX[10:8]
                // nodeID =  CPUID_Fn8000001E_ECX[7:0]
                int nodeId = (int)(thread.ExtData[0x1e, 2] & 0xff);

                if (coreIdRead != lastCoreId)
                {
                    coreId++;
                }
                lastCoreId = coreIdRead;

                _processor.AppendThread(thread, nodeId, coreId);
            }

            Update();
        }
Exemple #8
0
            public void AppendThread(CpuId thread, int numaId, int coreId)
            {
                NumaNode node = null;

                foreach (NumaNode n in Nodes)
                {
                    if (n.NodeId == numaId)
                    {
                        node = n;
                        break;
                    }
                }

                if (node == null)
                {
                    node = new NumaNode(_cpu, numaId);
                    Nodes.Add(node);
                }

                if (thread != null)
                {
                    node.AppendThread(thread, coreId);
                }
            }
Exemple #9
0
            public void UpdateSensors()
            {
                // CPUID cpu = threads.FirstOrDefault();
                CpuId cpu = Threads[0];

                if (cpu == null)
                {
                    return;
                }


                var previousAffinity = ThreadAffinity.Set(cpu.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 _, out _);

                // MSRC001_029A
                // total_energy [31:0]
                DateTime sampleTime = DateTime.Now;
                uint     eax;

                Ring0.ReadMsr(MSR_CORE_ENERGY_STAT, out eax, out _);
                uint totalEnergy = eax;

                // MSRC001_0293
                // CurHwPstate [24:22]
                // CurCpuVid [21:14]
                // CurCpuDfsId [13:8]
                // CurCpuFid [7:0]
                Ring0.ReadMsr(MSR_HARDWARE_PSTATE_STATUS, out eax, out _);
                int curCpuVid   = (int)((eax >> 14) & 0xff);
                int curCpuDfsId = (int)((eax >> 8) & 0x3f);
                int curCpuFid   = (int)(eax & 0xff);

                // MSRC001_0064 + x
                // IddDiv [31:30]
                // IddValue [29:22]
                // CpuVid [21:14]
                // CpuDfsId [13:8]
                // CpuFid [7:0]
                // Ring0.ReadMsr(MSR_PSTATE_0 + (uint)CurHwPstate, out eax, out edx);
                // int IddDiv = (int)((eax >> 30) & 0x03);
                // int IddValue = (int)((eax >> 22) & 0xff);
                // int CpuVid = (int)((eax >> 14) & 0xff);
                ThreadAffinity.Set(previousAffinity);

                // clock
                // CoreCOF is (Core::X86::Msr::PStateDef[CpuFid[7:0]] / Core::X86::Msr::PStateDef[CpuDfsId]) * 200
                double clock = 200.0;

                _busSpeed ??= _cpu.Sensors.FirstOrDefault(x => x.Name == "Bus Speed");
                if (_busSpeed?.Value.HasValue == true && _busSpeed.Value > 0)
                {
                    clock = (double)(_busSpeed.Value * 2);
                }

                _clock.Value = (float)(curCpuFid / (double)curCpuDfsId * clock);

                // multiplier
                _multiplier.Value = (float)(curCpuFid / (double)curCpuDfsId * 2.0);

                // Voltage
                const double vidStep = 0.00625;
                double       vcc     = 1.550 - vidStep * curCpuVid;

                _vcore.Value = (float)vcc;

                // 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))
                {
                    _power.Value = (float)energy;
                }
            }
Exemple #10
0
            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);
                }
            }