Hardware/CPU/IntelCPU.cs
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
branchMiniDisplay
changeset 444 9b09e2ee0968
parent 425 520bca5f2a7d
permissions -rw-r--r--
Front View plug-in does not init if no sensor added.
Fixing some format to make strings shorter.
Now trying to start SoundGraphAccess.exe process from same directory.
Packed mode now can display three sensors along with the current time.
moel@1
     1
/*
moel@1
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@1
     6
 
moel@424
     7
  Copyright (C) 2009-2014 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	
moel@1
     9
*/
moel@1
    10
moel@1
    11
using System;
moel@219
    12
using System.Globalization;
moel@219
    13
using System.Text;
moel@1
    14
moel@1
    15
namespace OpenHardwareMonitor.Hardware.CPU {
moel@191
    16
  internal sealed class IntelCPU : GenericCPU {
moel@46
    17
moel@219
    18
    private enum Microarchitecture {
moel@219
    19
      Unknown,
moel@264
    20
      NetBurst,
moel@219
    21
      Core,
moel@219
    22
      Atom,
moel@249
    23
      Nehalem,
moel@350
    24
      SandyBridge,
moel@396
    25
      IvyBridge,
moel@425
    26
      Haswell,
moel@426
    27
      Broadwell,
moel@426
    28
      Silvermont
moel@219
    29
    }
moel@219
    30
moel@195
    31
    private readonly Sensor[] coreTemperatures;
moel@306
    32
    private readonly Sensor packageTemperature;
moel@195
    33
    private readonly Sensor[] coreClocks;
moel@195
    34
    private readonly Sensor busClock;
moel@321
    35
    private readonly Sensor[] powerSensors;
moel@63
    36
moel@219
    37
    private readonly Microarchitecture microarchitecture;
moel@219
    38
    private readonly double timeStampCounterMultiplier;
moel@79
    39
moel@1
    40
    private const uint IA32_THERM_STATUS_MSR = 0x019C;
moel@4
    41
    private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
moel@44
    42
    private const uint IA32_PERF_STATUS = 0x0198;
moel@46
    43
    private const uint MSR_PLATFORM_INFO = 0xCE;
moel@306
    44
    private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1;
moel@317
    45
    private const uint MSR_RAPL_POWER_UNIT = 0x606;
moel@317
    46
    private const uint MSR_PKG_ENERY_STATUS = 0x611;
moel@321
    47
    private const uint MSR_DRAM_ENERGY_STATUS = 0x619;
moel@317
    48
    private const uint MSR_PP0_ENERY_STATUS = 0x639;
moel@320
    49
    private const uint MSR_PP1_ENERY_STATUS = 0x641;
moel@317
    50
moel@321
    51
    private readonly uint[] energyStatusMSRs = { MSR_PKG_ENERY_STATUS, 
moel@321
    52
      MSR_PP0_ENERY_STATUS, MSR_PP1_ENERY_STATUS, MSR_DRAM_ENERGY_STATUS };
moel@321
    53
    private readonly string[] powerSensorLabels = 
moel@321
    54
      { "CPU Package", "CPU Cores", "CPU Graphics", "CPU DRAM" };
moel@317
    55
    private float energyUnitMultiplier = 0;
moel@321
    56
    private DateTime[] lastEnergyTime;
moel@321
    57
    private uint[] lastEnergyConsumed;
moel@317
    58
moel@1
    59
moel@69
    60
    private float[] Floats(float f) {
moel@69
    61
      float[] result = new float[coreCount];
moel@69
    62
      for (int i = 0; i < coreCount; i++)
moel@69
    63
        result[i] = f;
moel@69
    64
      return result;
moel@69
    65
    }
moel@69
    66
moel@249
    67
    private float[] GetTjMaxFromMSR() {
moel@249
    68
      uint eax, edx;
moel@249
    69
      float[] result = new float[coreCount];
moel@249
    70
      for (int i = 0; i < coreCount; i++) {
moel@249
    71
        if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
moel@249
    72
          out edx, 1UL << cpuid[i][0].Thread)) {
moel@249
    73
          result[i] = (eax >> 16) & 0xFF;
moel@249
    74
        } else {
moel@249
    75
          result[i] = 100;
moel@249
    76
        }
moel@249
    77
      }
moel@249
    78
      return result;
moel@249
    79
    }
moel@249
    80
moel@191
    81
    public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
moel@321
    82
      : base(processorIndex, cpuid, settings) {
moel@219
    83
      // set tjMax
moel@69
    84
      float[] tjMax;
moel@49
    85
      switch (family) {
moel@49
    86
        case 0x06: {
moel@49
    87
            switch (model) {
moel@219
    88
              case 0x0F: // Intel Core 2 (65nm)
moel@219
    89
                microarchitecture = Microarchitecture.Core;
moel@49
    90
                switch (stepping) {
moel@49
    91
                  case 0x06: // B2
moel@49
    92
                    switch (coreCount) {
moel@49
    93
                      case 2:
moel@69
    94
                        tjMax = Floats(80 + 10); break;
moel@49
    95
                      case 4:
moel@69
    96
                        tjMax = Floats(90 + 10); break;
moel@49
    97
                      default:
moel@69
    98
                        tjMax = Floats(85 + 10); break;
moel@49
    99
                    }
moel@69
   100
                    tjMax = Floats(80 + 10); break;
moel@49
   101
                  case 0x0B: // G0
moel@69
   102
                    tjMax = Floats(90 + 10); break;
moel@49
   103
                  case 0x0D: // M0
moel@69
   104
                    tjMax = Floats(85 + 10); break;
moel@49
   105
                  default:
moel@69
   106
                    tjMax = Floats(85 + 10); break;
moel@49
   107
                } break;
moel@219
   108
              case 0x17: // Intel Core 2 (45nm)
moel@219
   109
                microarchitecture = Microarchitecture.Core;
moel@69
   110
                tjMax = Floats(100); break;
moel@114
   111
              case 0x1C: // Intel Atom (45nm)
moel@219
   112
                microarchitecture = Microarchitecture.Atom;
moel@114
   113
                switch (stepping) {
moel@114
   114
                  case 0x02: // C0
moel@114
   115
                    tjMax = Floats(90); break;
moel@114
   116
                  case 0x0A: // A0, B0
moel@114
   117
                    tjMax = Floats(100); break;
moel@114
   118
                  default:
moel@114
   119
                    tjMax = Floats(90); break;
moel@191
   120
                } break;
moel@49
   121
              case 0x1A: // Intel Core i7 LGA1366 (45nm)
moel@49
   122
              case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
moel@249
   123
              case 0x1F: // Intel Core i5, i7 
moel@49
   124
              case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
moel@91
   125
              case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
moel@350
   126
              case 0x2E: // Intel Xeon Processor 7500 series (45nm)
moel@350
   127
              case 0x2F: // Intel Xeon Processor (32nm)
moel@219
   128
                microarchitecture = Microarchitecture.Nehalem;
moel@249
   129
                tjMax = GetTjMaxFromMSR();
moel@249
   130
                break;
moel@249
   131
              case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
moel@350
   132
              case 0x2D: // Next Generation Intel Xeon, i7 3xxx LGA2011 (32nm)
moel@249
   133
                microarchitecture = Microarchitecture.SandyBridge;
moel@249
   134
                tjMax = GetTjMaxFromMSR();
moel@49
   135
                break;
moel@350
   136
              case 0x3A: // Intel Core i5, i7 3xxx LGA1155 (22nm)
moel@417
   137
              case 0x3E: // Intel Core i7 4xxx LGA2011 (22nm)
moel@350
   138
                microarchitecture = Microarchitecture.IvyBridge;
moel@350
   139
                tjMax = GetTjMaxFromMSR();
moel@350
   140
                break;
moel@425
   141
              case 0x3C: // Intel Core i5, i7 4xxx LGA1150 (22nm)              
moel@424
   142
              case 0x3F: // Intel Xeon E5-2600/1600 v3, Core i7-59xx
moel@424
   143
                         // LGA2011-v3, Haswell-E (22nm)
moel@425
   144
              case 0x45: // Intel Core i5, i7 4xxxU (22nm)
moel@424
   145
              case 0x46: 
moel@396
   146
                microarchitecture = Microarchitecture.Haswell;
moel@396
   147
                tjMax = GetTjMaxFromMSR();
moel@396
   148
                break;
moel@425
   149
              case 0x3D: // Intel Core M-5xxx (14nm)
moel@425
   150
                microarchitecture = Microarchitecture.Broadwell;
moel@425
   151
                tjMax = GetTjMaxFromMSR();
moel@425
   152
                break;
moel@426
   153
              case 0x36: // Intel Atom S1xxx, D2xxx, N2xxx (32nm)
moel@426
   154
                microarchitecture = Microarchitecture.Atom;
moel@426
   155
                tjMax = GetTjMaxFromMSR();
moel@426
   156
                break;
moel@426
   157
              case 0x37: // Intel Atom E3xxx, Z3xxx (22nm)
moel@426
   158
              case 0x4A:
moel@426
   159
              case 0x4D: // Intel Atom C2xxx (22nm)
moel@426
   160
              case 0x5A:
moel@426
   161
              case 0x5D:
moel@426
   162
                microarchitecture = Microarchitecture.Silvermont;
moel@426
   163
                tjMax = GetTjMaxFromMSR();
moel@426
   164
                break;
moel@49
   165
              default:
moel@219
   166
                microarchitecture = Microarchitecture.Unknown;
moel@321
   167
                tjMax = Floats(100);
moel@219
   168
                break;
moel@49
   169
            }
moel@49
   170
          } break;
moel@264
   171
        case 0x0F: {
moel@264
   172
            switch (model) {
moel@264
   173
              case 0x00: // Pentium 4 (180nm)
moel@264
   174
              case 0x01: // Pentium 4 (130nm)
moel@264
   175
              case 0x02: // Pentium 4 (130nm)
moel@264
   176
              case 0x03: // Pentium 4, Celeron D (90nm)
moel@264
   177
              case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
moel@264
   178
              case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
moel@264
   179
                microarchitecture = Microarchitecture.NetBurst;
moel@321
   180
                tjMax = Floats(100);
moel@264
   181
                break;
moel@264
   182
              default:
moel@264
   183
                microarchitecture = Microarchitecture.Unknown;
moel@264
   184
                tjMax = Floats(100);
moel@264
   185
                break;
moel@264
   186
            }
moel@264
   187
          } break;
moel@219
   188
        default:
moel@219
   189
          microarchitecture = Microarchitecture.Unknown;
moel@321
   190
          tjMax = Floats(100);
moel@219
   191
          break;
moel@219
   192
      }
moel@219
   193
moel@219
   194
      // set timeStampCounterMultiplier
moel@219
   195
      switch (microarchitecture) {
moel@264
   196
        case Microarchitecture.NetBurst:
moel@219
   197
        case Microarchitecture.Atom:
moel@219
   198
        case Microarchitecture.Core: {
moel@219
   199
            uint eax, edx;
moel@236
   200
            if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
moel@321
   201
              timeStampCounterMultiplier =
moel@219
   202
                ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
moel@219
   203
            }
moel@219
   204
          } break;
moel@321
   205
        case Microarchitecture.Nehalem:
moel@350
   206
        case Microarchitecture.SandyBridge:
moel@396
   207
        case Microarchitecture.IvyBridge:
moel@425
   208
        case Microarchitecture.Haswell: 
moel@426
   209
        case Microarchitecture.Broadwell:
moel@426
   210
        case Microarchitecture.Silvermont: {
moel@219
   211
            uint eax, edx;
moel@236
   212
            if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
moel@219
   213
              timeStampCounterMultiplier = (eax >> 8) & 0xff;
moel@219
   214
            }
moel@219
   215
          } break;
moel@350
   216
        default: 
moel@350
   217
          timeStampCounterMultiplier = 0;
moel@350
   218
          break;
moel@49
   219
      }
moel@1
   220
moel@306
   221
      // check if processor supports a digital thermal sensor at core level
moel@191
   222
      if (cpuid[0][0].Data.GetLength(0) > 6 &&
moel@350
   223
        (cpuid[0][0].Data[6, 0] & 1) != 0 && 
moel@350
   224
        microarchitecture != Microarchitecture.Unknown) 
moel@350
   225
      {
moel@44
   226
        coreTemperatures = new Sensor[coreCount];
moel@44
   227
        for (int i = 0; i < coreTemperatures.Length; i++) {
moel@134
   228
          coreTemperatures[i] = new Sensor(CoreString(i), i,
moel@321
   229
            SensorType.Temperature, this, new[] { 
moel@63
   230
              new ParameterDescription(
moel@306
   231
                "TjMax [°C]", "TjMax temperature of the core sensor.\n" + 
moel@69
   232
                "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
moel@122
   233
              new ParameterDescription("TSlope [°C]", 
moel@122
   234
                "Temperature slope of the digital thermal sensor.\n" + 
moel@165
   235
                "Temperature = TjMax - TSlope * Value.", 1)}, settings);
moel@155
   236
          ActivateSensor(coreTemperatures[i]);
moel@44
   237
        }
moel@44
   238
      } else {
moel@44
   239
        coreTemperatures = new Sensor[0];
moel@1
   240
      }
moel@49
   241
moel@306
   242
      // check if processor supports a digital thermal sensor at package level
moel@306
   243
      if (cpuid[0][0].Data.GetLength(0) > 6 &&
moel@350
   244
        (cpuid[0][0].Data[6, 0] & 0x40) != 0 && 
moel@350
   245
        microarchitecture != Microarchitecture.Unknown) 
moel@350
   246
      {
moel@321
   247
        packageTemperature = new Sensor("CPU Package",
moel@321
   248
          coreTemperatures.Length, SensorType.Temperature, this, new[] { 
moel@306
   249
              new ParameterDescription(
moel@306
   250
                "TjMax [°C]", "TjMax temperature of the package sensor.\n" + 
moel@306
   251
                "Temperature = TjMax - TSlope * Value.", tjMax[0]), 
moel@306
   252
              new ParameterDescription("TSlope [°C]", 
moel@306
   253
                "Temperature slope of the digital thermal sensor.\n" + 
moel@306
   254
                "Temperature = TjMax - TSlope * Value.", 1)}, settings);
moel@306
   255
        ActivateSensor(packageTemperature);
moel@321
   256
      }
moel@306
   257
moel@191
   258
      busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
moel@44
   259
      coreClocks = new Sensor[coreCount];
moel@44
   260
      for (int i = 0; i < coreClocks.Length; i++) {
moel@49
   261
        coreClocks[i] =
moel@165
   262
          new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
moel@350
   263
        if (HasTimeStampCounter && microarchitecture != Microarchitecture.Unknown)
moel@79
   264
          ActivateSensor(coreClocks[i]);
moel@44
   265
      }
moel@191
   266
moel@350
   267
      if (microarchitecture == Microarchitecture.SandyBridge ||
moel@396
   268
          microarchitecture == Microarchitecture.IvyBridge ||
moel@425
   269
          microarchitecture == Microarchitecture.Haswell ||
moel@426
   270
          microarchitecture == Microarchitecture.Broadwell || 
moel@426
   271
          microarchitecture == Microarchitecture.Silvermont) 
moel@350
   272
      {
moel@321
   273
        powerSensors = new Sensor[energyStatusMSRs.Length];
moel@321
   274
        lastEnergyTime = new DateTime[energyStatusMSRs.Length];
moel@321
   275
        lastEnergyConsumed = new uint[energyStatusMSRs.Length];
moel@321
   276
moel@317
   277
        uint eax, edx;
moel@317
   278
        if (Ring0.Rdmsr(MSR_RAPL_POWER_UNIT, out eax, out edx))
moel@426
   279
          switch (microarchitecture) {
moel@426
   280
            case Microarchitecture.Silvermont:
moel@426
   281
              energyUnitMultiplier = 1.0e-6f * (1 << (int)((eax >> 8) & 0x1F));
moel@426
   282
              break;
moel@426
   283
            default:
moel@426
   284
              energyUnitMultiplier = 1.0f / (1 << (int)((eax >> 8) & 0x1F));
moel@426
   285
              break;
moel@426
   286
          }
moel@321
   287
        if (energyUnitMultiplier != 0) {
moel@321
   288
          for (int i = 0; i < energyStatusMSRs.Length; i++) {
moel@321
   289
            if (!Ring0.Rdmsr(energyStatusMSRs[i], out eax, out edx))
moel@321
   290
              continue;
moel@317
   291
moel@321
   292
            lastEnergyTime[i] = DateTime.UtcNow;
moel@321
   293
            lastEnergyConsumed[i] = eax;
moel@321
   294
            powerSensors[i] = new Sensor(powerSensorLabels[i], i,
moel@321
   295
              SensorType.Power, this, settings);
moel@321
   296
            ActivateSensor(powerSensors[i]);
moel@321
   297
          }
moel@317
   298
        }
moel@317
   299
      }
moel@317
   300
moel@191
   301
      Update();
moel@1
   302
    }
moel@1
   303
moel@191
   304
    protected override uint[] GetMSRs() {
moel@321
   305
      return new[] {
moel@191
   306
        MSR_PLATFORM_INFO,
moel@191
   307
        IA32_PERF_STATUS ,
moel@191
   308
        IA32_THERM_STATUS_MSR,
moel@306
   309
        IA32_TEMPERATURE_TARGET,
moel@317
   310
        IA32_PACKAGE_THERM_STATUS,
moel@317
   311
        MSR_RAPL_POWER_UNIT,
moel@317
   312
        MSR_PKG_ENERY_STATUS,
moel@321
   313
        MSR_DRAM_ENERGY_STATUS,
moel@320
   314
        MSR_PP0_ENERY_STATUS,
moel@320
   315
        MSR_PP1_ENERY_STATUS
moel@191
   316
      };
moel@1
   317
    }
moel@1
   318
moel@219
   319
    public override string GetReport() {
moel@219
   320
      StringBuilder r = new StringBuilder();
moel@219
   321
      r.Append(base.GetReport());
moel@219
   322
moel@264
   323
      r.Append("Microarchitecture: ");
moel@264
   324
      r.AppendLine(microarchitecture.ToString());
moel@219
   325
      r.Append("Time Stamp Counter Multiplier: ");
moel@219
   326
      r.AppendLine(timeStampCounterMultiplier.ToString(
moel@219
   327
        CultureInfo.InvariantCulture));
moel@219
   328
      r.AppendLine();
moel@219
   329
moel@219
   330
      return r.ToString();
moel@219
   331
    }
moel@219
   332
moel@191
   333
    public override void Update() {
moel@191
   334
      base.Update();
moel@1
   335
moel@1
   336
      for (int i = 0; i < coreTemperatures.Length; i++) {
moel@46
   337
        uint eax, edx;
moel@418
   338
        // if reading is valid
moel@418
   339
        if (Ring0.RdmsrTx(IA32_THERM_STATUS_MSR, out eax, out edx,
moel@418
   340
            1UL << cpuid[i][0].Thread) && (eax & 0x80000000) != 0) 
moel@418
   341
        {
moel@418
   342
          // get the dist from tjMax from bits 22:16
moel@418
   343
          float deltaT = ((eax & 0x007F0000) >> 16);
moel@418
   344
          float tjMax = coreTemperatures[i].Parameters[0].Value;
moel@418
   345
          float tSlope = coreTemperatures[i].Parameters[1].Value;
moel@418
   346
          coreTemperatures[i].Value = tjMax - tSlope * deltaT;
moel@418
   347
        } else {
moel@418
   348
          coreTemperatures[i].Value = null;
moel@79
   349
        }
moel@24
   350
      }
moel@24
   351
moel@306
   352
      if (packageTemperature != null) {
moel@306
   353
        uint eax, edx;
moel@418
   354
        // if reading is valid
moel@418
   355
        if (Ring0.RdmsrTx(IA32_PACKAGE_THERM_STATUS, out eax, out edx,
moel@418
   356
            1UL << cpuid[0][0].Thread) && (eax & 0x80000000) != 0) 
moel@418
   357
        {
moel@306
   358
          // get the dist from tjMax from bits 22:16
moel@306
   359
          float deltaT = ((eax & 0x007F0000) >> 16);
moel@306
   360
          float tjMax = packageTemperature.Parameters[0].Value;
moel@306
   361
          float tSlope = packageTemperature.Parameters[1].Value;
moel@306
   362
          packageTemperature.Value = tjMax - tSlope * deltaT;
moel@306
   363
        } else {
moel@306
   364
          packageTemperature.Value = null;
moel@306
   365
        }
moel@306
   366
      }
moel@306
   367
moel@350
   368
      if (HasTimeStampCounter && timeStampCounterMultiplier > 0) {
moel@191
   369
        double newBusClock = 0;
moel@191
   370
        uint eax, edx;
moel@191
   371
        for (int i = 0; i < coreClocks.Length; i++) {
moel@191
   372
          System.Threading.Thread.Sleep(1);
moel@236
   373
          if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
moel@321
   374
            1UL << cpuid[i][0].Thread)) {
moel@321
   375
            newBusClock =
moel@219
   376
              TimeStampCounterFrequency / timeStampCounterMultiplier;
moel@250
   377
            switch (microarchitecture) {
moel@250
   378
              case Microarchitecture.Nehalem: {
moel@250
   379
                  uint multiplier = eax & 0xff;
moel@250
   380
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   381
                } break;
moel@350
   382
              case Microarchitecture.SandyBridge:
moel@396
   383
              case Microarchitecture.IvyBridge:
moel@425
   384
              case Microarchitecture.Haswell: 
moel@426
   385
              case Microarchitecture.Broadwell:
moel@426
   386
              case Microarchitecture.Silvermont: {
moel@250
   387
                  uint multiplier = (eax >> 8) & 0xff;
moel@250
   388
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   389
                } break;
moel@250
   390
              default: {
moel@321
   391
                  double multiplier =
moel@250
   392
                    ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
moel@250
   393
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   394
                } break;
moel@321
   395
            }
moel@321
   396
          } else {
moel@201
   397
            // if IA32_PERF_STATUS is not available, assume TSC frequency
moel@201
   398
            coreClocks[i].Value = (float)TimeStampCounterFrequency;
moel@46
   399
          }
moel@44
   400
        }
moel@191
   401
        if (newBusClock > 0) {
moel@191
   402
          this.busClock.Value = (float)newBusClock;
moel@191
   403
          ActivateSensor(this.busClock);
moel@191
   404
        }
moel@44
   405
      }
moel@317
   406
moel@321
   407
      if (powerSensors != null) {
moel@321
   408
        foreach (Sensor sensor in powerSensors) {
moel@321
   409
          if (sensor == null)
moel@321
   410
            continue;
moel@317
   411
moel@321
   412
          uint eax, edx;
moel@321
   413
          if (!Ring0.Rdmsr(energyStatusMSRs[sensor.Index], out eax, out edx))
moel@321
   414
            continue;
moel@317
   415
moel@317
   416
          DateTime time = DateTime.UtcNow;
moel@317
   417
          uint energyConsumed = eax;
moel@321
   418
          float deltaTime =
moel@321
   419
            (float)(time - lastEnergyTime[sensor.Index]).TotalSeconds;
moel@321
   420
          if (deltaTime < 0.01)
moel@321
   421
            continue;
moel@321
   422
moel@321
   423
          sensor.Value = energyUnitMultiplier * unchecked(
moel@321
   424
            energyConsumed - lastEnergyConsumed[sensor.Index]) / deltaTime;
moel@321
   425
          lastEnergyTime[sensor.Index] = time;
moel@321
   426
          lastEnergyConsumed[sensor.Index] = energyConsumed;
moel@317
   427
        }
moel@317
   428
      }
moel@46
   429
    }
moel@191
   430
  }
moel@1
   431
}