Improved the implementation for the AMD 10h family CPU clock speeds.
1.1 --- a/Hardware/CPU/AMD0FCPU.cs Mon Sep 27 23:48:41 2010 +0000
1.2 +++ b/Hardware/CPU/AMD0FCPU.cs Thu Sep 30 16:51:09 2010 +0000
1.3 @@ -92,7 +92,7 @@
1.4 for (int i = 0; i < coreClocks.Length; i++) {
1.5 coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock,
1.6 this, settings);
1.7 - if (hasTSC)
1.8 + if (HasTimeStampCounter)
1.9 ActivateSensor(coreClocks[i]);
1.10 }
1.11
1.12 @@ -138,7 +138,7 @@
1.13 }
1.14 }
1.15
1.16 - if (hasTSC) {
1.17 + if (HasTimeStampCounter) {
1.18 double newBusClock = 0;
1.19
1.20 for (int i = 0; i < coreClocks.Length; i++) {
1.21 @@ -151,11 +151,12 @@
1.22 // 8-13 hold StartFID, we don't use that here.
1.23 double curMP = 0.5 * ((eax & 0x3F) + 8);
1.24 double maxMP = 0.5 * ((eax >> 16 & 0x3F) + 8);
1.25 - coreClocks[i].Value = (float)(curMP * MaxClock / maxMP);
1.26 - newBusClock = (float)(MaxClock / maxMP);
1.27 + coreClocks[i].Value =
1.28 + (float)(curMP * TimeStampCounterFrequency / maxMP);
1.29 + newBusClock = (float)(TimeStampCounterFrequency / maxMP);
1.30 } else {
1.31 // Fail-safe value - if the code above fails, we'll use this instead
1.32 - coreClocks[i].Value = (float)MaxClock;
1.33 + coreClocks[i].Value = (float)TimeStampCounterFrequency;
1.34 }
1.35 }
1.36
2.1 --- a/Hardware/CPU/AMD10CPU.cs Mon Sep 27 23:48:41 2010 +0000
2.2 +++ b/Hardware/CPU/AMD10CPU.cs Thu Sep 30 16:51:09 2010 +0000
2.3 @@ -36,7 +36,10 @@
2.4 */
2.5
2.6 using System;
2.7 +using System.Collections.Generic;
2.8 +using System.Diagnostics;
2.9 using System.Globalization;
2.10 +using System.Runtime.InteropServices;
2.11 using System.Text;
2.12 using System.Threading;
2.13
2.14 @@ -47,16 +50,22 @@
2.15 private readonly Sensor coreTemperature;
2.16 private readonly Sensor[] coreClocks;
2.17 private readonly Sensor busClock;
2.18 -
2.19 +
2.20 + private const uint PERF_CTL_0 = 0xC0010000;
2.21 + private const uint PERF_CTR_0 = 0xC0010004;
2.22 + private const uint P_STATE_0 = 0xC0010064;
2.23 private const uint COFVID_STATUS = 0xC0010071;
2.24 - private const uint P_STATE_0 = 0xC0010064;
2.25
2.26 private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3;
2.27 private const ushort MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1203;
2.28 private const uint REPORTED_TEMPERATURE_CONTROL_REGISTER = 0xA4;
2.29 -
2.30 +
2.31 private readonly uint miscellaneousControlAddress;
2.32
2.33 + private double timeStampCounterMultiplier;
2.34 +
2.35 + private StringBuilder debug = new StringBuilder();
2.36 +
2.37 public AMD10CPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
2.38 : base(processorIndex, cpuid, settings)
2.39 {
2.40 @@ -76,15 +85,87 @@
2.41 for (int i = 0; i < coreClocks.Length; i++) {
2.42 coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock,
2.43 this, settings);
2.44 - if (hasTSC)
2.45 + if (HasTimeStampCounter)
2.46 ActivateSensor(coreClocks[i]);
2.47 }
2.48
2.49 + // set affinity to the first thread for all frequency estimations
2.50 + IntPtr thread = NativeMethods.GetCurrentThread();
2.51 + UIntPtr mask = NativeMethods.SetThreadAffinityMask(thread,
2.52 + (UIntPtr)(1L << cpuid[0][0].Thread));
2.53 +
2.54 + uint ctlEax, ctlEdx;
2.55 + WinRing0.Rdmsr(PERF_CTL_0, out ctlEax, out ctlEdx);
2.56 + uint ctrEax, ctrEdx;
2.57 + WinRing0.Rdmsr(PERF_CTR_0, out ctrEax, out ctrEdx);
2.58 +
2.59 + timeStampCounterMultiplier = estimateTimeStampCounterMultiplier();
2.60 +
2.61 + // restore the performance counter registers
2.62 + WinRing0.Wrmsr(PERF_CTL_0, ctlEax, ctlEdx);
2.63 + WinRing0.Wrmsr(PERF_CTR_0, ctrEax, ctrEdx);
2.64 +
2.65 + // restore the thread affinity.
2.66 + NativeMethods.SetThreadAffinityMask(thread, mask);
2.67 +
2.68 Update();
2.69 }
2.70
2.71 + private double estimateTimeStampCounterMultiplier() {
2.72 + // preload the function
2.73 + estimateTimeStampCounterMultiplier(0);
2.74 + estimateTimeStampCounterMultiplier(0);
2.75 +
2.76 + // estimate the multiplier
2.77 + List<double> estimate = new List<double>(3);
2.78 + for (int i = 0; i < 3; i++)
2.79 + estimate.Add(estimateTimeStampCounterMultiplier(0.025));
2.80 + estimate.Sort();
2.81 + return estimate[1];
2.82 + }
2.83 +
2.84 + private double estimateTimeStampCounterMultiplier(double timeWindow) {
2.85 + uint eax, edx;
2.86 +
2.87 + // select event "076h CPU Clocks not Halted" and enable the counter
2.88 + WinRing0.Wrmsr(PERF_CTL_0,
2.89 + (1 << 22) | // enable performance counter
2.90 + (1 << 17) | // count events in user mode
2.91 + (1 << 16) | // count events in operating-system mode
2.92 + 0x76, 0x00000000);
2.93 +
2.94 + // set the counter to 0
2.95 + WinRing0.Wrmsr(PERF_CTR_0, 0, 0);
2.96 +
2.97 + long ticks = (long)(timeWindow * Stopwatch.Frequency);
2.98 + uint lsbBegin, msbBegin, lsbEnd, msbEnd;
2.99 +
2.100 + long timeBegin = Stopwatch.GetTimestamp() +
2.101 + (long)Math.Ceiling(0.001 * ticks);
2.102 + long timeEnd = timeBegin + ticks;
2.103 + while (Stopwatch.GetTimestamp() < timeBegin) { }
2.104 + WinRing0.Rdmsr(PERF_CTR_0, out lsbBegin, out msbBegin);
2.105 + while (Stopwatch.GetTimestamp() < timeEnd) { }
2.106 + WinRing0.Rdmsr(PERF_CTR_0, out lsbEnd, out msbEnd);
2.107 +
2.108 + WinRing0.Rdmsr(COFVID_STATUS, out eax, out edx);
2.109 + uint cpuDid = (eax >> 6) & 7;
2.110 + uint cpuFid = eax & 0x1F;
2.111 + double coreMultiplier = MultiplierFromIDs(cpuDid, cpuFid);
2.112 +
2.113 + ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
2.114 + ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
2.115 +
2.116 + double coreFrequency = 1e-6 *
2.117 + (((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
2.118 + (timeEnd - timeBegin);
2.119 +
2.120 + double busFrequency = coreFrequency / coreMultiplier;
2.121 + return 0.5 * Math.Round(2 * TimeStampCounterFrequency / busFrequency);
2.122 + }
2.123 +
2.124 protected override uint[] GetMSRs() {
2.125 - return new uint[] { P_STATE_0, COFVID_STATUS };
2.126 + return new uint[] { PERF_CTL_0, PERF_CTR_0, P_STATE_0, COFVID_STATUS };
2.127 }
2.128
2.129 public override string GetReport() {
2.130 @@ -94,12 +175,18 @@
2.131 r.Append("Miscellaneous Control Address: 0x");
2.132 r.AppendLine((miscellaneousControlAddress).ToString("X",
2.133 CultureInfo.InvariantCulture));
2.134 + r.Append("Time Stamp Counter Multiplier: ");
2.135 + r.AppendLine(timeStampCounterMultiplier.ToString(
2.136 + CultureInfo.InvariantCulture));
2.137 + r.AppendLine();
2.138 +
2.139 + r.Append(debug);
2.140 r.AppendLine();
2.141
2.142 return r.ToString();
2.143 }
2.144
2.145 - private double MultiplierFromIDs(uint divisorID, uint frequencyID) {
2.146 + private static double MultiplierFromIDs(uint divisorID, uint frequencyID) {
2.147 return 0.5 * (frequencyID + 0x10) / (1 << (int)divisorID);
2.148 }
2.149
2.150 @@ -118,35 +205,29 @@
2.151 }
2.152 }
2.153
2.154 - if (hasTSC) {
2.155 + if (HasTimeStampCounter) {
2.156 double newBusClock = 0;
2.157
2.158 for (int i = 0; i < coreClocks.Length; i++) {
2.159 Thread.Sleep(1);
2.160
2.161 uint curEax, curEdx;
2.162 - uint maxEax, maxEdx;
2.163 if (WinRing0.RdmsrTx(COFVID_STATUS, out curEax, out curEdx,
2.164 - (UIntPtr)(1L << cpuid[i][0].Thread)) &&
2.165 - WinRing0.RdmsrTx(P_STATE_0, out maxEax, out maxEdx,
2.166 (UIntPtr)(1L << cpuid[i][0].Thread)))
2.167 {
2.168 // 8:6 CpuDid: current core divisor ID
2.169 // 5:0 CpuFid: current core frequency ID
2.170 - uint curCpuDid = (curEax >> 6) & 7;
2.171 - uint curCpuFid = curEax & 0x1F;
2.172 - double multiplier = MultiplierFromIDs(curCpuDid, curCpuFid);
2.173 + uint cpuDid = (curEax >> 6) & 7;
2.174 + uint cpuFid = curEax & 0x1F;
2.175 + double multiplier = MultiplierFromIDs(cpuDid, cpuFid);
2.176
2.177 - // we assume that the max multiplier (used for the TSC)
2.178 - // can be found in the P_STATE_0 MSR
2.179 - uint maxCpuDid = (maxEax >> 6) & 7;
2.180 - uint maxCpuFid = maxEax & 0x1F;
2.181 - double maxMultiplier = MultiplierFromIDs(maxCpuDid, maxCpuFid);
2.182 -
2.183 - coreClocks[i].Value = (float)(multiplier * MaxClock / maxMultiplier);
2.184 - newBusClock = (float)(MaxClock / maxMultiplier);
2.185 + coreClocks[i].Value =
2.186 + (float)(multiplier * TimeStampCounterFrequency /
2.187 + timeStampCounterMultiplier);
2.188 + newBusClock =
2.189 + (float)(TimeStampCounterFrequency / timeStampCounterMultiplier);
2.190 } else {
2.191 - coreClocks[i].Value = (float)MaxClock;
2.192 + coreClocks[i].Value = (float)TimeStampCounterFrequency;
2.193 }
2.194 }
2.195
2.196 @@ -155,6 +236,17 @@
2.197 ActivateSensor(this.busClock);
2.198 }
2.199 }
2.200 - }
2.201 + }
2.202 +
2.203 + private static class NativeMethods {
2.204 + private const string KERNEL = "kernel32.dll";
2.205 +
2.206 + [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
2.207 + public static extern UIntPtr
2.208 + SetThreadAffinityMask(IntPtr handle, UIntPtr mask);
2.209 +
2.210 + [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
2.211 + public static extern IntPtr GetCurrentThread();
2.212 + }
2.213 }
2.214 }
3.1 --- a/Hardware/CPU/GenericCPU.cs Mon Sep 27 23:48:41 2010 +0000
3.2 +++ b/Hardware/CPU/GenericCPU.cs Thu Sep 30 16:51:09 2010 +0000
3.3 @@ -55,13 +55,13 @@
3.4 protected readonly int coreCount;
3.5 protected readonly string name;
3.6
3.7 - protected readonly bool hasTSC;
3.8 - protected readonly bool invariantTSC;
3.9 - private readonly double estimatedMaxClock;
3.10 + private readonly bool hasTimeStampCounter;
3.11 + private readonly bool isInvariantTimeStampCounter;
3.12 + private readonly double estimatedTimeStampCounterFrequency;
3.13
3.14 private ulong lastTimeStampCount;
3.15 private long lastTime;
3.16 - private double maxClock;
3.17 + private double timeStampCounterFrequency;
3.18
3.19 private readonly Vendor vendor;
3.20
3.21 @@ -89,19 +89,19 @@
3.22 this.coreCount = cpuid.Length;
3.23 this.name = cpuid[0][0].Name;
3.24
3.25 - // check if processor has TSC
3.26 + // check if processor has a TSC
3.27 if (cpuid[0][0].Data.GetLength(0) > 1
3.28 && (cpuid[0][0].Data[1, 3] & 0x10) != 0)
3.29 - hasTSC = true;
3.30 + hasTimeStampCounter = true;
3.31 else
3.32 - hasTSC = false;
3.33 + hasTimeStampCounter = false;
3.34
3.35 - // check if processor supports invariant TSC
3.36 + // check if processor supports an invariant TSC
3.37 if (cpuid[0][0].ExtData.GetLength(0) > 7
3.38 && (cpuid[0][0].ExtData[7, 3] & 0x100) != 0)
3.39 - invariantTSC = true;
3.40 + isInvariantTimeStampCounter = true;
3.41 else
3.42 - invariantTSC = false;
3.43 + isInvariantTimeStampCounter = false;
3.44
3.45 if (coreCount > 1)
3.46 totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this, settings);
3.47 @@ -119,30 +119,30 @@
3.48 ActivateSensor(totalLoad);
3.49 }
3.50
3.51 - if (hasTSC)
3.52 - estimatedMaxClock = EstimateMaxClock();
3.53 + if (hasTimeStampCounter)
3.54 + estimatedTimeStampCounterFrequency = EstimateTimeStampCounterFrequency();
3.55 else
3.56 - estimatedMaxClock = 0;
3.57 - maxClock = estimatedMaxClock;
3.58 + estimatedTimeStampCounterFrequency = 0;
3.59 + timeStampCounterFrequency = estimatedTimeStampCounterFrequency;
3.60
3.61 lastTimeStampCount = 0;
3.62 lastTime = 0;
3.63 }
3.64
3.65 - private static double EstimateMaxClock() {
3.66 + private static double EstimateTimeStampCounterFrequency() {
3.67 // preload the function
3.68 - EstimateMaxClock(0);
3.69 - EstimateMaxClock(0);
3.70 + EstimateTimeStampCounterFrequency(0);
3.71 + EstimateTimeStampCounterFrequency(0);
3.72
3.73 - // estimate the max clock in MHz
3.74 - List<double> estimatedMaxClocks = new List<double>(3);
3.75 + // estimate the frequency in MHz
3.76 + List<double> estimatedFrequency = new List<double>(3);
3.77 for (int i = 0; i < 3; i++)
3.78 - estimatedMaxClocks.Add(1e-6 * EstimateMaxClock(0.025));
3.79 - estimatedMaxClocks.Sort();
3.80 - return estimatedMaxClocks[1];
3.81 + estimatedFrequency.Add(1e-6 * EstimateTimeStampCounterFrequency(0.025));
3.82 + estimatedFrequency.Sort();
3.83 + return estimatedFrequency[1];
3.84 }
3.85
3.86 - private static double EstimateMaxClock(double timeWindow) {
3.87 + private static double EstimateTimeStampCounterFrequency(double timeWindow) {
3.88 long ticks = (long)(timeWindow * Stopwatch.Frequency);
3.89 uint lsbBegin, msbBegin, lsbEnd, msbEnd;
3.90
3.91 @@ -195,12 +195,13 @@
3.92 Environment.NewLine);
3.93 r.AppendFormat("Threads per Core: {0}{1}", cpuid[0].Length,
3.94 Environment.NewLine);
3.95 - r.AppendLine("TSC: " +
3.96 - (hasTSC ? (invariantTSC ? "Invariant" : "Not Invariant") : "None"));
3.97 r.AppendLine(string.Format(CultureInfo.InvariantCulture,
3.98 "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
3.99 + r.AppendLine("Time Stamp Counter: " + (hasTimeStampCounter ? (
3.100 + isInvariantTimeStampCounter ? "Invariant" : "Not Invariant") : "None"));
3.101 r.AppendLine(string.Format(CultureInfo.InvariantCulture,
3.102 - "Max Clock: {0} MHz", Math.Round(maxClock * 100) * 0.01));
3.103 + "Time Stamp Counter Frequency: {0} MHz",
3.104 + Math.Round(timeStampCounterFrequency * 100) * 0.01));
3.105 r.AppendLine();
3.106
3.107 uint[] msrArray = GetMSRs();
3.108 @@ -239,22 +240,27 @@
3.109 get { return HardwareType.CPU; }
3.110 }
3.111
3.112 - protected double MaxClock {
3.113 - get { return maxClock; }
3.114 + public bool HasTimeStampCounter {
3.115 + get { return hasTimeStampCounter; }
3.116 + }
3.117 +
3.118 + public double TimeStampCounterFrequency {
3.119 + get { return timeStampCounterFrequency; }
3.120 }
3.121
3.122 public override void Update() {
3.123 - if (hasTSC) {
3.124 + if (hasTimeStampCounter) {
3.125 uint lsb, msb;
3.126 WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
3.127 long time = Stopwatch.GetTimestamp();
3.128 ulong timeStampCount = ((ulong)msb << 32) | lsb;
3.129 double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
3.130 if (delta > 0.5) {
3.131 - if (invariantTSC)
3.132 - maxClock = (timeStampCount - lastTimeStampCount) / (1e6 * delta);
3.133 + if (isInvariantTimeStampCounter)
3.134 + timeStampCounterFrequency =
3.135 + (timeStampCount - lastTimeStampCount) / (1e6 * delta);
3.136 else
3.137 - maxClock = estimatedMaxClock;
3.138 + timeStampCounterFrequency = estimatedTimeStampCounterFrequency;
3.139
3.140 lastTimeStampCount = timeStampCount;
3.141 lastTime = time;
4.1 --- a/Hardware/CPU/IntelCPU.cs Mon Sep 27 23:48:41 2010 +0000
4.2 +++ b/Hardware/CPU/IntelCPU.cs Thu Sep 30 16:51:09 2010 +0000
4.3 @@ -145,7 +145,7 @@
4.4 for (int i = 0; i < coreClocks.Length; i++) {
4.5 coreClocks[i] =
4.6 new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
4.7 - if (hasTSC)
4.8 + if (HasTimeStampCounter)
4.9 ActivateSensor(coreClocks[i]);
4.10 }
4.11
4.12 @@ -182,7 +182,7 @@
4.13 }
4.14 }
4.15
4.16 - if (hasTSC) {
4.17 + if (HasTimeStampCounter) {
4.18 double newBusClock = 0;
4.19 uint eax, edx;
4.20 for (int i = 0; i < coreClocks.Length; i++) {
4.21 @@ -191,9 +191,10 @@
4.22 (UIntPtr)(1L << cpuid[i][0].Thread))) {
4.23 if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
4.24 uint nehalemMultiplier = eax & 0xff;
4.25 - coreClocks[i].Value =
4.26 - (float)(nehalemMultiplier * MaxClock / maxNehalemMultiplier);
4.27 - newBusClock = (float)(MaxClock / maxNehalemMultiplier);
4.28 + coreClocks[i].Value =(float)(nehalemMultiplier *
4.29 + TimeStampCounterFrequency / maxNehalemMultiplier);
4.30 + newBusClock =
4.31 + (float)(TimeStampCounterFrequency / maxNehalemMultiplier);
4.32 } else { // Core 2
4.33 uint multiplier = (eax >> 8) & 0x1f;
4.34 uint maxMultiplier = (edx >> 8) & 0x1f;
4.35 @@ -201,13 +202,15 @@
4.36 uint factor = (multiplier << 1) | ((eax >> 14) & 1);
4.37 uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
4.38 if (maxFactor > 0) {
4.39 - coreClocks[i].Value = (float)(factor * MaxClock / maxFactor);
4.40 - newBusClock = (float)(2 * MaxClock / maxFactor);
4.41 + coreClocks[i].Value =
4.42 + (float)(factor * TimeStampCounterFrequency / maxFactor);
4.43 + newBusClock =
4.44 + (float)(2 * TimeStampCounterFrequency / maxFactor);
4.45 }
4.46 }
4.47 } else { // Intel Pentium 4
4.48 - // if IA32_PERF_STATUS is not available, assume maxClock
4.49 - coreClocks[i].Value = (float)MaxClock;
4.50 + // if IA32_PERF_STATUS is not available, assume TSC frequency
4.51 + coreClocks[i].Value = (float)TimeStampCounterFrequency;
4.52 }
4.53 }
4.54 if (newBusClock > 0) {
5.1 --- a/Hardware/WinRing0.cs Mon Sep 27 23:48:41 2010 +0000
5.2 +++ b/Hardware/WinRing0.cs Thu Sep 30 16:51:09 2010 +0000
5.3 @@ -90,10 +90,13 @@
5.4 public delegate bool ReadPciConfigDwordExDelegate(uint pciAddress,
5.5 uint regAddress, out uint value);
5.6 public delegate bool WritePciConfigDwordExDelegate(uint pciAddress,
5.7 - uint regAddress, uint value);
5.8 + uint regAddress, uint value);
5.9 + public delegate bool RdtscDelegate(out uint eax, out uint edx);
5.10 public delegate bool RdtscTxDelegate(out uint eax, out uint edx,
5.11 + UIntPtr threadAffinityMask);
5.12 + public delegate bool WrmsrDelegate(uint index, uint eax, uint edx);
5.13 + public delegate bool WrmsrTxDelegate(uint index, uint eax, uint edx,
5.14 UIntPtr threadAffinityMask);
5.15 - public delegate bool RdtscDelegate(out uint eax, out uint edx);
5.16
5.17 private static readonly InitializeOlsDelegate InitializeOls =
5.18 CreateDelegate<InitializeOlsDelegate>("InitializeOls");
5.19 @@ -116,10 +119,14 @@
5.20 CreateDelegate<ReadPciConfigDwordExDelegate>("ReadPciConfigDwordEx");
5.21 public static readonly WritePciConfigDwordExDelegate WritePciConfigDwordEx =
5.22 CreateDelegate<WritePciConfigDwordExDelegate>("WritePciConfigDwordEx");
5.23 - public static readonly RdtscTxDelegate RdtscTx =
5.24 - CreateDelegate<RdtscTxDelegate>("RdtscTx");
5.25 public static readonly RdtscDelegate Rdtsc =
5.26 CreateDelegate<RdtscDelegate>("Rdtsc");
5.27 + public static readonly RdtscTxDelegate RdtscTx =
5.28 + CreateDelegate<RdtscTxDelegate>("RdtscTx");
5.29 + public static readonly WrmsrDelegate Wrmsr =
5.30 + CreateDelegate<WrmsrDelegate>("Wrmsr");
5.31 + public static readonly WrmsrTxDelegate WrmsrTx =
5.32 + CreateDelegate<WrmsrTxDelegate>("WrmsrTx");
5.33
5.34 private static T CreateDelegate<T>(string entryPoint) where T : class {
5.35 DllImportAttribute attribute = new DllImportAttribute(GetDllName());
6.1 --- a/Properties/AssemblyVersion.cs Mon Sep 27 23:48:41 2010 +0000
6.2 +++ b/Properties/AssemblyVersion.cs Thu Sep 30 16:51:09 2010 +0000
6.3 @@ -37,5 +37,5 @@
6.4
6.5 using System.Reflection;
6.6
6.7 -[assembly: AssemblyVersion("0.1.37.17")]
6.8 -[assembly: AssemblyInformationalVersion("0.1.37.17 Alpha")]
6.9 \ No newline at end of file
6.10 +[assembly: AssemblyVersion("0.1.37.23")]
6.11 +[assembly: AssemblyInformationalVersion("0.1.37.23 Alpha")]
6.12 \ No newline at end of file