mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
Add processors tab (#2166)
This commit is contained in:
@@ -63,7 +63,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
StorageSpaceUsageInMB = prototype.StorageSpaceUsageInMB,
|
StorageSpaceUsageInMB = prototype.StorageSpaceUsageInMB,
|
||||||
Version = prototype.Version,
|
Version = prototype.Version,
|
||||||
MinServerMemory = prototype.MinServerMemory,
|
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 });
|
return Task.FromResult(new InitializeViewResult { ViewInfo = this.serverViewInfo, Context = context });
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
//
|
//
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -30,6 +32,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
public NumericServerProperty MaxServerMemory { get; set; }
|
public NumericServerProperty MaxServerMemory { get; set; }
|
||||||
public NumericServerProperty MinServerMemory { get; set; }
|
public NumericServerProperty MinServerMemory { get; set; }
|
||||||
|
public bool AutoProcessorAffinityMaskForAll { get; set; }
|
||||||
|
public bool AutoProcessorAffinityIOMaskForAll { get; set; }
|
||||||
|
public List<NumaNode> NumaNodes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NumericServerProperty
|
public class NumericServerProperty
|
||||||
@@ -38,4 +43,16 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
public int MinimumValue { get; set; }
|
public int MinimumValue { get; set; }
|
||||||
public int Value { get; set; }
|
public int Value { get; set; }
|
||||||
}
|
}
|
||||||
|
public class NumaNode
|
||||||
|
{
|
||||||
|
public string NumaNodeId { get; set; }
|
||||||
|
public List<ProcessorAffinity> Processors { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProcessorAffinity
|
||||||
|
{
|
||||||
|
public string ProcessorId { get; set; }
|
||||||
|
public bool Affinity { get; set; }
|
||||||
|
public bool IOAffinity { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class to manage affinity for 64 processors in an independent manner for I/O as well as processors
|
||||||
|
/// </summary>
|
||||||
|
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
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
private class Affinity
|
||||||
|
{
|
||||||
|
private int affinityMaskCfg = 0;
|
||||||
|
private int affinityMaskRun = 0;
|
||||||
|
/// <summary>
|
||||||
|
/// Affinity ConfigValue reflecting sys.configurations table
|
||||||
|
/// </summary>
|
||||||
|
public int AffinityMaskCfg { get { return affinityMaskCfg; } set { affinityMaskCfg = value; } }
|
||||||
|
/// <summary>
|
||||||
|
/// Affinity RunValue reflecting sys.configurations table
|
||||||
|
/// </summary>
|
||||||
|
public int AffinityMaskRun { get { return affinityMaskRun; } set { affinityMaskRun = value; } }
|
||||||
|
|
||||||
|
/// Reset the affinities to default values.
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
affinityMaskCfg = 0;
|
||||||
|
affinityMaskRun = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a mask for masking the N processors
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="numProcessors"> number of processors to mask</param>
|
||||||
|
/// <returns>Mask for numProcessors</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="processorNumber">The CPU number for which affinity is to be set. Range: [0, 63]</param>
|
||||||
|
/// <return>true: this is the last CPU which has affinity bit set;
|
||||||
|
/// false: some other CPU than processorNumber is having affinity bit set.</return>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="affinityConfig">returns the affinity for first 32 processors. null if not changed</param>
|
||||||
|
/// <param name="affinity64Config">return the affinity for CPUs 33-64. null if not changed.</param>
|
||||||
|
public void GetAffinityMasksIfChanged(out int? affinityConfig, out int? affinity64Config)
|
||||||
|
{
|
||||||
|
affinityConfig = affinity64Config = null;
|
||||||
|
affinityConfig = affinity.AffinityMaskCfg;
|
||||||
|
affinity64Config = affinity64.AffinityMaskCfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="basedOnConfigValue">true: use ConfigValue mask for test
|
||||||
|
/// false: use RunValue mask for test.</param>
|
||||||
|
/// <returns>true: The Affinity mode is set to "auto".; false: The affinity mode is not auto.</returns>
|
||||||
|
public bool IsAutoAffinity(bool basedOnConfigValue)
|
||||||
|
{
|
||||||
|
return basedOnConfigValue ? (affinity.AffinityMaskCfg == 0 && affinity64.AffinityMaskCfg == 0)
|
||||||
|
: (affinity.AffinityMaskRun == 0 && affinity64.AffinityMaskRun == 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the affinity for CPU processorNumber as enabled or disabled.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="processorNumber">The CPU number for which affinity is queried. Range: [0, 63]</param>
|
||||||
|
/// <return>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.
|
||||||
|
/// </return>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the desired CPU's affinity.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="processorNumber">the CPU number for which affinity is set. Range: [0, 63] Must be valid.</param>
|
||||||
|
/// <param name="affinityEnabled">
|
||||||
|
/// 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.
|
||||||
|
/// </return>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reset the affinities to default values.
|
||||||
|
/// </summary>
|
||||||
|
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.
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,10 +5,15 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.SqlServer.Management.Smo;
|
using Microsoft.SqlServer.Management.Smo;
|
||||||
|
using SMO = Microsoft.SqlServer.Management.Smo;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||||
using Microsoft.SqlServer.Management.Common;
|
using Microsoft.SqlServer.Management.Common;
|
||||||
using Microsoft.SqlTools.ServiceLayer.ServerConfigurations;
|
using Microsoft.SqlTools.ServiceLayer.ServerConfigurations;
|
||||||
using Microsoft.SqlTools.Utility;
|
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
|
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
||||||
{
|
{
|
||||||
@@ -287,6 +292,45 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
this.currentState.MinMemory = value;
|
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<NumaNode> NumaNodes
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.currentState.NumaNodes;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.currentState.NumaNodes = value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -321,6 +365,37 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
{
|
{
|
||||||
Microsoft.SqlServer.Management.Smo.Server server = this.dataContainer.Server;
|
Microsoft.SqlServer.Management.Smo.Server server = this.dataContainer.Server;
|
||||||
bool changesMade = false;
|
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);
|
changesMade = UpdateMemoryValues(this.dataContainer.Server);
|
||||||
|
|
||||||
@@ -349,6 +424,156 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
}
|
}
|
||||||
return changesMade;
|
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;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// This will send data for KJ specific things
|
||||||
|
/// Also Checks if Alter needs to be generated
|
||||||
|
/// </summary>
|
||||||
|
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
|
#endregion
|
||||||
|
|
||||||
public void ApplyInfoToPrototype(ServerInfo serverInfo)
|
public void ApplyInfoToPrototype(ServerInfo serverInfo)
|
||||||
@@ -373,6 +598,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
this.StorageSpaceUsageInMB = (int)(serverInfo.StorageSpaceUsageInMB);
|
this.StorageSpaceUsageInMB = (int)(serverInfo.StorageSpaceUsageInMB);
|
||||||
this.MaxServerMemory = serverInfo.MaxServerMemory;
|
this.MaxServerMemory = serverInfo.MaxServerMemory;
|
||||||
this.MinServerMemory = serverInfo.MinServerMemory;
|
this.MinServerMemory = serverInfo.MinServerMemory;
|
||||||
|
this.AutoProcessorAffinityMaskForAll = serverInfo.AutoProcessorAffinityMaskForAll;
|
||||||
|
this.AutoProcessorAffinityIOMaskForAll = serverInfo.AutoProcessorAffinityIOMaskForAll;
|
||||||
|
this.NumaNodes = serverInfo.NumaNodes.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -403,19 +631,53 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
private string serviceTier = String.Empty;
|
private string serviceTier = String.Empty;
|
||||||
private int reservedStorageSizeMB = 0;
|
private int reservedStorageSizeMB = 0;
|
||||||
private int storageSpaceUsageInMB = 0;
|
private int storageSpaceUsageInMB = 0;
|
||||||
|
|
||||||
private NumericServerProperty minMemory;
|
private NumericServerProperty minMemory;
|
||||||
private NumericServerProperty maxMemory;
|
private NumericServerProperty maxMemory;
|
||||||
|
private bool autoProcessorAffinityMaskForAll = false;
|
||||||
|
private bool autoProcessorAffinityIOMaskForAll = false;
|
||||||
|
private List<NumaNode> numaNodes = new List<NumaNode>();
|
||||||
|
|
||||||
private bool initialized = false;
|
private bool initialized = false;
|
||||||
private Server server;
|
private Server server;
|
||||||
private CDataContainer context;
|
private CDataContainer context;
|
||||||
private ServerConfigService configService;
|
private ServerConfigService configService;
|
||||||
|
private AffinityManager affinityManagerIOMask;
|
||||||
|
private AffinityManager affinityManagerProcessorMask;
|
||||||
|
|
||||||
private bool isYukonOrLater = false;
|
private bool isYukonOrLater = false;
|
||||||
|
private bool isSqlServer64Bit;
|
||||||
|
private bool isIOAffinitySupported = false;
|
||||||
|
|
||||||
ConfigProperty serverMaxMemoryProperty;
|
ConfigProperty serverMaxMemoryProperty;
|
||||||
ConfigProperty serverMinMemoryProperty;
|
ConfigProperty serverMinMemoryProperty;
|
||||||
#endregion
|
#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
|
#region Properties
|
||||||
|
|
||||||
// General properties
|
// General properties
|
||||||
@@ -835,11 +1097,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (this.initialized)
|
if (this.initialized)
|
||||||
{
|
{
|
||||||
Logger.Error(SR.PropertyNotInitialized("MinMemory"));
|
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<NumaNode> 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
|
public Microsoft.SqlServer.Management.Smo.Server Server
|
||||||
{
|
{
|
||||||
@@ -904,10 +1235,15 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.configService = service;
|
this.configService = service;
|
||||||
this.isYukonOrLater = (this.server.Information.Version.Major >= 9);
|
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.serverMaxMemoryProperty = this.configService.GetServerSmoConfig(server, this.configService.MaxServerMemoryPropertyNumber);
|
||||||
this.serverMinMemoryProperty = this.configService.GetServerSmoConfig(server, this.configService.MinServerMemoryPropertyNumber);
|
this.serverMinMemoryProperty = this.configService.GetServerSmoConfig(server, this.configService.MinServerMemoryPropertyNumber);
|
||||||
this.minMemory = new NumericServerProperty();
|
this.minMemory = new NumericServerProperty();
|
||||||
this.maxMemory = new NumericServerProperty();
|
this.maxMemory = new NumericServerProperty();
|
||||||
|
this.NumaNodes = new List<NumaNode>();
|
||||||
|
|
||||||
LoadData();
|
LoadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -939,6 +1275,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
result.version = this.version;
|
result.version = this.version;
|
||||||
result.maxMemory = this.maxMemory;
|
result.maxMemory = this.maxMemory;
|
||||||
result.minMemory = this.minMemory;
|
result.minMemory = this.minMemory;
|
||||||
|
result.autoProcessorAffinityMaskForAll = this.autoProcessorAffinityMaskForAll;
|
||||||
|
result.autoProcessorAffinityIOMaskForAll = this.autoProcessorAffinityIOMaskForAll;
|
||||||
|
result.numaNodes = this.numaNodes;
|
||||||
result.server = this.server;
|
result.server = this.server;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -965,6 +1304,19 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
this.serviceTier = server.ServiceTier;
|
this.serviceTier = server.ServiceTier;
|
||||||
this.storageSpaceUsageInMB = server.UsedStorageSizeMB;
|
this.storageSpaceUsageInMB = server.UsedStorageSizeMB;
|
||||||
LoadMemoryProperties();
|
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()
|
private void LoadMemoryProperties()
|
||||||
@@ -977,6 +1329,50 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
|
|||||||
this.minMemory.MaximumValue = serverMinMemoryProperty.Maximum;
|
this.minMemory.MaximumValue = serverMinMemoryProperty.Maximum;
|
||||||
this.minMemory.MinimumValue = serverMinMemoryProperty.Minimum;
|
this.minMemory.MinimumValue = serverMinMemoryProperty.Minimum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="affinityConfig">returns the affinity for first 32 processors. null if not changed</param>
|
||||||
|
/// <param name="affinity64Config">return the affinity for CPUs 33-64. null if not changed.</param>
|
||||||
|
private List<NumaNode> GetNumaNodes()
|
||||||
|
{
|
||||||
|
List<NumaNode> results = new List<NumaNode>();
|
||||||
|
foreach (SMO.NumaNode node in this.server.AffinityInfo.NumaNodes)
|
||||||
|
{
|
||||||
|
var processors = new List<ProcessorAffinity>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,9 +87,13 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
|
|||||||
MaxServerMemory = result.MaxServerMemory
|
MaxServerMemory = result.MaxServerMemory
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// original memory settings
|
||||||
|
var originalMinMemory = result.MinServerMemory.Value;
|
||||||
|
var originalMaxMemory = result.MaxServerMemory.Value;
|
||||||
|
|
||||||
// Change memory settings
|
// Change memory settings
|
||||||
serverInfo.MinServerMemory.Value = 10;
|
serverInfo.MinServerMemory.Value = serverInfo.MinServerMemory.MinimumValue;
|
||||||
serverInfo.MaxServerMemory.Value = 500;
|
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.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");
|
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, Is.Not.Null);
|
||||||
Assert.That(result.MinServerMemory.Value, Is.EqualTo(serverInfo.MinServerMemory.Value), "Server property should be equal after update");
|
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");
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test Processors for Sql Server
|
||||||
|
/// </summary>
|
||||||
|
[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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user