From 16c7e323567023b08200ab35b2bfb2a5042385e0 Mon Sep 17 00:00:00 2001 From: Barbara Valdez <34872381+barbaravaldez@users.noreply.github.com> Date: Mon, 21 Aug 2023 13:24:48 -0700 Subject: [PATCH] Add processors tab (#2166) --- .../ObjectTypes/Server/ServerHandler.cs | 5 +- .../ObjectTypes/Server/ServerInfo.cs | 17 + .../ObjectTypes/Server/ServerProcessor.cs | 221 ++++++++++ .../ObjectTypes/Server/ServerPrototype.cs | 402 +++++++++++++++++- .../ObjectManagement/ServerHandlerTests.cs | 59 ++- 5 files changed, 698 insertions(+), 6 deletions(-) create mode 100644 src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerProcessor.cs diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerHandler.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerHandler.cs index dc691d25..55b4f153 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerHandler.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerHandler.cs @@ -63,7 +63,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement StorageSpaceUsageInMB = prototype.StorageSpaceUsageInMB, Version = prototype.Version, MinServerMemory = prototype.MinServerMemory, - MaxServerMemory = prototype.MaxServerMemory + MaxServerMemory = prototype.MaxServerMemory, + AutoProcessorAffinityMaskForAll = prototype.AutoProcessorAffinityMaskForAll, + AutoProcessorAffinityIOMaskForAll = prototype.AutoProcessorAffinityIOMaskForAll, + NumaNodes = prototype.NumaNodes }; } return Task.FromResult(new InitializeViewResult { ViewInfo = this.serverViewInfo, Context = context }); diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerInfo.cs index a900fd7a..9d8cad7c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerInfo.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerInfo.cs @@ -4,6 +4,8 @@ // #nullable disable +using System.Collections.Generic; + namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement { /// @@ -30,6 +32,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement public string Version { get; set; } public NumericServerProperty MaxServerMemory { get; set; } public NumericServerProperty MinServerMemory { get; set; } + public bool AutoProcessorAffinityMaskForAll { get; set; } + public bool AutoProcessorAffinityIOMaskForAll { get; set; } + public List NumaNodes { get; set; } } public class NumericServerProperty @@ -38,4 +43,16 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement public int MinimumValue { get; set; } public int Value { get; set; } } + public class NumaNode + { + public string NumaNodeId { get; set; } + public List Processors { get; set; } + } + + public class ProcessorAffinity + { + public string ProcessorId { get; set; } + public bool Affinity { get; set; } + public bool IOAffinity { get; set; } + } } \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerProcessor.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerProcessor.cs new file mode 100644 index 00000000..08b05351 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerProcessor.cs @@ -0,0 +1,221 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections; +using SMO = Microsoft.SqlServer.Management.Smo; + +namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement.ObjectTypes.Server +{ + /// + /// Class to manage affinity for 64 processors in an independent manner for I/O as well as processors + /// + internal sealed class AffinityManager + { + public const int MAX64CPU = 64; + public const int MAX32CPU = 32; + public const int MAX_IO_CPU_SUPPORTED = 64; + + public BitArray initialIOAffinityArray = new BitArray(64, false); + + private static string[] configFields = new string[] + { + "Minimum", + "Maximum", + "Dynamic", + "ConfigValue", + "RunValue" + }; + #region class Affinity representing data related to each affinity mask + /// + /// The Affinity structure represents one row of the sys.configuration table for + /// that particular affinity (affinity,affinty64 for processor or I/O). + /// It also stores the old value of the affinity for optimizing server query. + /// + private class Affinity + { + private int affinityMaskCfg = 0; + private int affinityMaskRun = 0; + /// + /// Affinity ConfigValue reflecting sys.configurations table + /// + public int AffinityMaskCfg { get { return affinityMaskCfg; } set { affinityMaskCfg = value; } } + /// + /// Affinity RunValue reflecting sys.configurations table + /// + public int AffinityMaskRun { get { return affinityMaskRun; } set { affinityMaskRun = value; } } + + /// Reset the affinities to default values. + /// + public void Clear() + { + affinityMaskCfg = 0; + affinityMaskRun = 0; + } + }; + #endregion + + /// + /// Generates a mask for masking the N processors + /// + /// number of processors to mask + /// Mask for numProcessors + private int GetMaskAllProcessors(int numProcessors) + { + if (numProcessors < MAX32CPU) + { + try + { + return System.Convert.ToInt32(Math.Pow(2, numProcessors) - 1); + } + catch (System.OverflowException) + { + return int.MaxValue; + } + } + else + { + // Earlier code used int.MaxValue for return which was buggy + // since in 2's compliment notation -1 is the one with all bits + // set to 1. [anchals] + return (int)-1; + } + } + + /// + /// Lets the caller know if only one CPU is selected. The processor number for the only set CPU is + /// passed in. The method is optimized this way otherwise it needs to count the number of 1's in the + /// affinity mask to see if only one CPU is selected. + /// + /// The CPU number for which affinity is to be set. Range: [0, 63] + /// true: this is the last CPU which has affinity bit set; + /// false: some other CPU than processorNumber is having affinity bit set. + public bool IsThisLastSelectedProcessor(int processorNumber) + { + if (processorNumber < MAX32CPU) + { + return (affinity.AffinityMaskCfg == (1 << processorNumber)) && (affinity64.AffinityMaskCfg == 0); + } + else + { + return (affinity64.AffinityMaskCfg == (1 << (processorNumber - MAX32CPU))) && (affinity.AffinityMaskCfg == 0); + } + } + + /// + /// Get affinity masks for first 32 and next 32 processors (total 64 processors) if the + /// processor masks have been modified after being read from the server. + /// + /// returns the affinity for first 32 processors. null if not changed + /// return the affinity for CPUs 33-64. null if not changed. + public void GetAffinityMasksIfChanged(out int? affinityConfig, out int? affinity64Config) + { + affinityConfig = affinity64Config = null; + affinityConfig = affinity.AffinityMaskCfg; + affinity64Config = affinity64.AffinityMaskCfg; + } + + + /// + /// Checks if automatic affinity is chosen. Happens when mask for all 64 processors is reset/0. + /// Tells whether the CPU is in auto affinity mode or not. (i.e. all CPU mask bits are 0) + /// + /// true: use ConfigValue mask for test + /// false: use RunValue mask for test. + /// true: The Affinity mode is set to "auto".; false: The affinity mode is not auto. + public bool IsAutoAffinity(bool basedOnConfigValue) + { + return basedOnConfigValue ? (affinity.AffinityMaskCfg == 0 && affinity64.AffinityMaskCfg == 0) + : (affinity.AffinityMaskRun == 0 && affinity64.AffinityMaskRun == 0); + + } + + /// + /// Get the affinity for CPU processorNumber as enabled or disabled. + /// + /// The CPU number for which affinity is queried. Range: [0, 63] + /// true: affinity is enabled for the CPU; false: affinity disabled + /// /// Note: if the function returns false then the SQL Server might be in auto mode also, + /// as in auto mode all Processor Affinity Mask bits are 0. + /// + public bool GetAffinity(int processorNumber, bool showConfigValues) + { + int aux = 0, mask = 0; + if (processorNumber < MAX32CPU) + { + aux = showConfigValues ? affinity.AffinityMaskCfg : affinity.AffinityMaskRun; + mask = 1 << processorNumber; + } + else + { + aux = showConfigValues ? affinity64.AffinityMaskCfg : affinity64.AffinityMaskRun; + mask = 1 << (processorNumber - MAX32CPU); + } + + return (aux & mask) != 0; + } + + /// + /// Set the desired CPU's affinity. + /// + /// the CPU number for which affinity is set. Range: [0, 63] Must be valid. + /// + /// true: set affinity bit for the CPU; false: reset CPU bit for the particular processor. + /// Note: if false is passed then the SQL Server might be set in auto mode also, + /// as in auto mode all Processor Affinity Mask bits are 0. + /// + public void SetAffinity(int processorNumber, bool affinityEnabled) + { + int mask = 0; + + if (processorNumber < MAX32CPU) + { + mask = 1 << processorNumber; + if (affinityEnabled) + { + affinity.AffinityMaskCfg |= mask; + } + else + { + affinity.AffinityMaskCfg &= ~mask; + } + } + else + { + mask = 1 << (processorNumber - MAX32CPU); + if (affinityEnabled) + { + affinity64.AffinityMaskCfg |= mask; + } + else + { + affinity64.AffinityMaskCfg &= ~mask; + } + + } + } + + public void InitializeAffinity(SMO.ConfigProperty affinity, SMO.ConfigProperty affinity64) + { + this.affinity.AffinityMaskCfg = affinity.ConfigValue; + this.affinity.AffinityMaskRun = affinity.RunValue; + this.affinity64.AffinityMaskCfg = affinity64.ConfigValue; + this.affinity64.AffinityMaskRun = affinity64.RunValue; + } + + /// + /// Reset the affinities to default values. + /// + public void Clear() + { + initialIOAffinityArray = new BitArray(64, false); + affinity.Clear(); + affinity64.Clear(); + } + + private Affinity affinity = new Affinity(); // affinity mask for first 32 processors + private Affinity affinity64 = new Affinity(); // affinity mask for next 32 (33-64) processors. + }; +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerPrototype.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerPrototype.cs index 760401a7..9b588dbb 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerPrototype.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerPrototype.cs @@ -5,10 +5,15 @@ using System; using Microsoft.SqlServer.Management.Smo; +using SMO = Microsoft.SqlServer.Management.Smo; using Microsoft.SqlTools.ServiceLayer.Management; using Microsoft.SqlServer.Management.Common; using Microsoft.SqlTools.ServiceLayer.ServerConfigurations; using Microsoft.SqlTools.Utility; +using System.Collections.Generic; +using Microsoft.SqlTools.ServiceLayer.ObjectManagement.ObjectTypes.Server; +using System.Linq; +using System.Collections; namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement { @@ -287,6 +292,45 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement this.currentState.MinMemory = value; } + } + + public bool AutoProcessorAffinityMaskForAll + { + get + { + return this.currentState.AutoProcessorAffinityMaskForAll; + } + set + { + this.currentState.AutoProcessorAffinityMaskForAll = value; + } + + } + + public bool AutoProcessorAffinityIOMaskForAll + { + get + { + return this.currentState.AutoProcessorAffinityMaskForAll; + } + set + { + this.currentState.AutoProcessorAffinityMaskForAll = value; + } + + } + + public List NumaNodes + { + get + { + return this.currentState.NumaNodes; + } + set + { + this.currentState.NumaNodes = value; + } + } #endregion @@ -321,6 +365,37 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement { Microsoft.SqlServer.Management.Smo.Server server = this.dataContainer.Server; bool changesMade = false; + bool alterServerConfig = false; + bool sendCPUAffinityBeforeIO = false; + bool sendIOAffinityBeforeCPU = false; + bool sentCpuAffinity = false; + + sendCPUAffinityBeforeIO = this.CheckCPUAffinityBeforeIO(server); + sendIOAffinityBeforeCPU = this.CheckIOAffinityBeforeCPU(server); + alterServerConfig = this.CheckIOAffinityTsqlGenerated(server); + if (!sendIOAffinityBeforeCPU) + { + SendDataForKJ(server); + sentCpuAffinity = true; + } + + if (alterServerConfig) + { + try + { + server.Configuration.Alter((sendCPUAffinityBeforeIO && sendIOAffinityBeforeCPU)); + } + finally + { + server.Configuration.Refresh(); + } + } + if (!sentCpuAffinity) + { + SendDataForKJ(server); + } + this.currentState.AffinityManagerProcessorMask.Clear(); + this.currentState.AffinityManagerIOMask.Clear(); changesMade = UpdateMemoryValues(this.dataContainer.Server); @@ -349,6 +424,156 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement } return changesMade; } + + private bool CheckCPUAffinityBeforeIO(SMO.Server smoServer) + { + for (int i = 0; i < this.NumaNodes.Count; i++) + { + SMO.NumaNode nNode = smoServer.AffinityInfo.NumaNodes[i]; + for (int cpuCount = 0; cpuCount < this.NumaNodes[i].Processors.Count; cpuCount++) + { + SMO.Cpu cpu = nNode.Cpus[cpuCount]; + if (cpu.GroupID == 0) + { + if (cpu.AffinityMask == this.NumaNodes[i].Processors[cpuCount].IOAffinity && cpu.AffinityMask) + { + //if Current IO affinity is equal to initial cpu.Affinity then script Cpu Affinity first + return true; + } + } + } + } + return false; + } + + private bool CheckIOAffinityBeforeCPU(SMO.Server smoServer) + { + for (int i = 0; i < this.NumaNodes.Count; i++) + { + SMO.NumaNode nNode = smoServer.AffinityInfo.NumaNodes[i]; + for (int cpuCount = 0; cpuCount < this.NumaNodes[i].Processors.Count; cpuCount++) + { + SMO.Cpu cpu = nNode.Cpus[cpuCount]; + if (cpu.GroupID == 0) + { + if (this.currentState.AffinityManagerIOMask.initialIOAffinityArray[cpu.ID] == this.NumaNodes[i].Processors[cpuCount].Affinity && this.currentState.AffinityManagerIOMask.initialIOAffinityArray[cpu.ID]) + { + //if Current IO affinity is equal to initial cpu.Affinity then script Cpu Affinity first + return true; + } + } + } + } + return false; + } + /// + /// This will send data for KJ specific things + /// Also Checks if Alter needs to be generated + /// + private void SendDataForKJ(SMO.Server smoServer) + { + BitArray finalCpuAffinity = new BitArray(64, false); + bool sendAffinityInfoAlter = false; + + if (this.AutoProcessorAffinityMaskForAll) + { + if (smoServer.AffinityInfo.AffinityType != Microsoft.SqlServer.Management.Smo.AffinityType.Auto) + { + smoServer.AffinityInfo.AffinityType = Microsoft.SqlServer.Management.Smo.AffinityType.Auto; + sendAffinityInfoAlter = true; + } + } + else + { + if (smoServer.AffinityInfo.AffinityType != Microsoft.SqlServer.Management.Smo.AffinityType.Manual) + { + smoServer.AffinityInfo.AffinityType = Microsoft.SqlServer.Management.Smo.AffinityType.Manual; + sendAffinityInfoAlter = true; + } + } + + for (int i = 0; i < this.NumaNodes.Count; i++) + { + SMO.NumaNode node = smoServer.AffinityInfo.NumaNodes[i]; + for (int cpuCount = 0; cpuCount < this.NumaNodes[i].Processors.Count; cpuCount++) + { + SMO.Cpu cpu = node.Cpus[cpuCount]; + if (this.NumaNodes[i].Processors[cpuCount].Affinity != cpu.AffinityMask) + { + sendAffinityInfoAlter = true; + if (!this.AutoProcessorAffinityMaskForAll) + { + cpu.AffinityMask = this.NumaNodes[i].Processors[cpuCount].Affinity; + } + } + } + } + + if (sendAffinityInfoAlter) + { + try + { + smoServer.AffinityInfo.Alter(); + smoServer.Configuration.Alter(); + } + finally + { + smoServer.AffinityInfo.Refresh(); + smoServer.Configuration.Refresh(); + } + } + + } + + private bool CheckIOAffinityTsqlGenerated(SMO.Server smoServer) + { + bool sendAlter = false; + bool send64AffinityIOAlter = false; + BitArray finalCpuIOAffinity = new BitArray(64, false); + for (int i = 0; i < this.NumaNodes.Count; i++) + { + SMO.NumaNode nNode = smoServer.AffinityInfo.NumaNodes[i]; + for (int cpuCount = 0; cpuCount < this.NumaNodes[i].Processors.Count; cpuCount++) + { + SMO.Cpu cpu = nNode.Cpus[cpuCount]; + if (cpu.GroupID == 0) + { + finalCpuIOAffinity[cpu.ID] = this.NumaNodes[i].Processors[cpuCount].IOAffinity; + if (this.currentState.AffinityManagerIOMask.initialIOAffinityArray[cpu.ID] != finalCpuIOAffinity[cpu.ID]) + { + if (cpu.ID < AffinityManager.MAX32CPU) + { + sendAlter = true; + } + else + { + send64AffinityIOAlter = true; + } + } + } + } + } + + if (sendAlter || send64AffinityIOAlter) + { + int[] intArray = new int[2]; + finalCpuIOAffinity.CopyTo(intArray, 0); + if (sendAlter) + { + smoServer.Configuration.AffinityIOMask.ConfigValue = intArray[0]; + } + if (send64AffinityIOAlter) + { + smoServer.Configuration.Affinity64IOMask.ConfigValue = intArray[1]; + } + //update current state initialIO after update + if (this.currentState.AffinityManagerIOMask.initialIOAffinityArray != finalCpuIOAffinity) + { + this.currentState.AffinityManagerIOMask.initialIOAffinityArray = finalCpuIOAffinity; + } + } + return (sendAlter || send64AffinityIOAlter); + } #endregion public void ApplyInfoToPrototype(ServerInfo serverInfo) @@ -373,6 +598,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement this.StorageSpaceUsageInMB = (int)(serverInfo.StorageSpaceUsageInMB); this.MaxServerMemory = serverInfo.MaxServerMemory; this.MinServerMemory = serverInfo.MinServerMemory; + this.AutoProcessorAffinityMaskForAll = serverInfo.AutoProcessorAffinityMaskForAll; + this.AutoProcessorAffinityIOMaskForAll = serverInfo.AutoProcessorAffinityIOMaskForAll; + this.NumaNodes = serverInfo.NumaNodes.ToList(); } /// @@ -403,19 +631,53 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement private string serviceTier = String.Empty; private int reservedStorageSizeMB = 0; private int storageSpaceUsageInMB = 0; - private NumericServerProperty minMemory; private NumericServerProperty maxMemory; + private bool autoProcessorAffinityMaskForAll = false; + private bool autoProcessorAffinityIOMaskForAll = false; + private List numaNodes = new List(); + private bool initialized = false; private Server server; private CDataContainer context; private ServerConfigService configService; + private AffinityManager affinityManagerIOMask; + private AffinityManager affinityManagerProcessorMask; + private bool isYukonOrLater = false; + private bool isSqlServer64Bit; + private bool isIOAffinitySupported = false; ConfigProperty serverMaxMemoryProperty; ConfigProperty serverMinMemoryProperty; #endregion + public AffinityManager AffinityManagerIOMask + { + get + { + return this.affinityManagerIOMask; + } + + set + { + this.affinityManagerIOMask = value; + } + } + + public AffinityManager AffinityManagerProcessorMask + { + get + { + return this.affinityManagerProcessorMask; + } + + set + { + this.affinityManagerProcessorMask = value; + } + } + #region Properties // General properties @@ -835,11 +1097,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement set { if (this.initialized) - { + { Logger.Error(SR.PropertyNotInitialized("MinMemory")); } - this.minMemory = value; + this.minMemory = value; } } @@ -866,6 +1128,75 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement } } + public bool AutoProcessorAffinityMaskForAll + { + get + { + if (!this.initialized) + { + LoadData(); + } + + return this.autoProcessorAffinityMaskForAll; + } + + set + { + if (this.initialized) + { + Logger.Error(SR.PropertyNotInitialized("AutoProcessorAffinityMaskForAll")); + } + + this.autoProcessorAffinityMaskForAll = value; + } + } + + public bool AutoProcessorAffinityIOMaskForAll + { + get + { + if (!this.initialized) + { + LoadData(); + } + + return this.autoProcessorAffinityIOMaskForAll; + } + + set + { + if (this.initialized) + { + Logger.Error(SR.PropertyNotInitialized("AutoProcessorAffinityIOMaskForAll")); + } + + this.autoProcessorAffinityIOMaskForAll = value; + } + } + + public List NumaNodes + { + get + { + if (!this.initialized) + { + LoadData(); + } + + return this.numaNodes; + } + + set + { + if (this.initialized) + { + Logger.Error(SR.PropertyNotInitialized("NumaNodes")); + } + + this.numaNodes = value; + } + } + public Microsoft.SqlServer.Management.Smo.Server Server { @@ -904,10 +1235,15 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement this.context = context; this.configService = service; this.isYukonOrLater = (this.server.Information.Version.Major >= 9); + this.isSqlServer64Bit = (this.server.Edition.Contains("(64 - bit)")); + this.affinityManagerIOMask = new AffinityManager(); + this.affinityManagerProcessorMask = new AffinityManager(); this.serverMaxMemoryProperty = this.configService.GetServerSmoConfig(server, this.configService.MaxServerMemoryPropertyNumber); this.serverMinMemoryProperty = this.configService.GetServerSmoConfig(server, this.configService.MinServerMemoryPropertyNumber); this.minMemory = new NumericServerProperty(); this.maxMemory = new NumericServerProperty(); + this.NumaNodes = new List(); + LoadData(); } @@ -939,6 +1275,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement result.version = this.version; result.maxMemory = this.maxMemory; result.minMemory = this.minMemory; + result.autoProcessorAffinityMaskForAll = this.autoProcessorAffinityMaskForAll; + result.autoProcessorAffinityIOMaskForAll = this.autoProcessorAffinityIOMaskForAll; + result.numaNodes = this.numaNodes; result.server = this.server; return result; } @@ -965,6 +1304,19 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement this.serviceTier = server.ServiceTier; this.storageSpaceUsageInMB = server.UsedStorageSizeMB; LoadMemoryProperties(); + try + { + this.affinityManagerIOMask.InitializeAffinity(this.server.Configuration.AffinityIOMask, this.server.Configuration.Affinity64IOMask); + this.isIOAffinitySupported = true; + } + catch + { + this.isIOAffinitySupported = false; + } + this.affinityManagerProcessorMask.InitializeAffinity(this.server.Configuration.AffinityMask, this.server.Configuration.Affinity64Mask); + + this.numaNodes = GetNumaNodes(); + GetAutoProcessorsAffinity(); } private void LoadMemoryProperties() @@ -977,6 +1329,50 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement this.minMemory.MaximumValue = serverMinMemoryProperty.Maximum; this.minMemory.MinimumValue = serverMinMemoryProperty.Minimum; } + + /// + /// Get affinity masks for first 32 and next 32 processors (total 64 processors) if the + /// processor masks have been modified after being read from the server. + /// + /// returns the affinity for first 32 processors. null if not changed + /// return the affinity for CPUs 33-64. null if not changed. + private List GetNumaNodes() + { + List results = new List(); + foreach (SMO.NumaNode node in this.server.AffinityInfo.NumaNodes) + { + var processors = new List(); + foreach (SMO.Cpu cpu in node.Cpus) + { + if (cpu.GroupID == 0) + { + var affinityIO = this.AffinityManagerIOMask.GetAffinity(cpu.ID, true); + if (!cpu.AffinityMask && this.isIOAffinitySupported && affinityIO) // if it's false then check if io affinity is checked + { + this.AffinityManagerIOMask.initialIOAffinityArray[cpu.ID] = true; + } + + // get affinityIO info if group id is 0 + processors.Add(new ProcessorAffinity() { ProcessorId = cpu.ID.ToString(), Affinity = cpu.AffinityMask, IOAffinity = affinityIO }); + } + } + var result = new NumaNode() { NumaNodeId = node.ID.ToString(), Processors = processors }; + results.Add(result); + } + return results; + } + + private void GetAutoProcessorsAffinity() + { + if (this.server.AffinityInfo.AffinityType == Microsoft.SqlServer.Management.Smo.AffinityType.Auto) + { + this.autoProcessorAffinityMaskForAll = this.autoProcessorAffinityIOMaskForAll = true; + } + else + { + this.autoProcessorAffinityMaskForAll = this.autoProcessorAffinityIOMaskForAll = false; + } + } } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ServerHandlerTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ServerHandlerTests.cs index 1684fe12..d8033276 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ServerHandlerTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ServerHandlerTests.cs @@ -87,9 +87,13 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement MaxServerMemory = result.MaxServerMemory }; + // original memory settings + var originalMinMemory = result.MinServerMemory.Value; + var originalMaxMemory = result.MaxServerMemory.Value; + // Change memory settings - serverInfo.MinServerMemory.Value = 10; - serverInfo.MaxServerMemory.Value = 500; + serverInfo.MinServerMemory.Value = serverInfo.MinServerMemory.MinimumValue; + serverInfo.MaxServerMemory.Value = serverInfo.MaxServerMemory.MaximumValue; Assert.That(result.MinServerMemory.Value, Is.Not.EqualTo(serverInfo.MinServerMemory.Value), "Server property should not be equal after update"); Assert.That(result.MaxServerMemory.Value, Is.Not.EqualTo(serverInfo.MaxServerMemory.Value), "Server property should not be equal after update"); @@ -100,6 +104,57 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement Assert.That(result, Is.Not.Null); Assert.That(result.MinServerMemory.Value, Is.EqualTo(serverInfo.MinServerMemory.Value), "Server property should be equal after update"); Assert.That(result.MaxServerMemory.Value, Is.EqualTo(serverInfo.MaxServerMemory.Value), "Server property should be equal after update"); + + // Reset to original values + serverInfo.MinServerMemory.Value = originalMinMemory; + serverInfo.MaxServerMemory.Value = originalMaxMemory; + await ObjectManagementTestUtils.SaveObject(requestParams, serverInfo); + } + } + + /// + /// Test Processors for Sql Server + /// + [Test] + public async Task GetProcessorsProperties() + { + var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", serverType: TestServerType.OnPrem); + using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo)) + { + var server = new Server(new ServerConnection(sqlConn)); + var serverHandler = new ServerHandler(ConnectionService.Instance); + + var requestParams = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", true, SqlObjectType.Server, "", ""); + var result = (ServerInfo)(await serverHandler.InitializeObjectView(requestParams)).ViewInfo.ObjectInfo; + ServerInfo serverInfo = new ServerInfo() + { + Name = result.Name, + HardwareGeneration = result.HardwareGeneration, + Language = result.Language, + MemoryInMB = result.MemoryInMB, + OperatingSystem = result.OperatingSystem, + Platform = result.Platform, + Processors = result.Processors, + IsClustered = result.IsClustered, + IsHadrEnabled = result.IsHadrEnabled, + IsPolyBaseInstalled = result.IsPolyBaseInstalled, + IsXTPSupported = result.IsXTPSupported, + Product = result.Product, + ReservedStorageSizeMB = result.ReservedStorageSizeMB, + RootDirectory = result.RootDirectory, + ServerCollation = result.ServerCollation, + ServiceTier = result.ServiceTier, + StorageSpaceUsageInMB = result.StorageSpaceUsageInMB, + Version = result.Version, + MinServerMemory = result.MinServerMemory, + MaxServerMemory = result.MaxServerMemory, + AutoProcessorAffinityMaskForAll = result.AutoProcessorAffinityMaskForAll, + AutoProcessorAffinityIOMaskForAll = result.AutoProcessorAffinityIOMaskForAll + }; + + Assert.That(result, Is.Not.Null); + Assert.That(result.AutoProcessorAffinityIOMaskForAll,Is.True, "Auto affinity should be default"); + Assert.That(result.AutoProcessorAffinityMaskForAll, Is.True, "Auto affinity should be default"); } } }