MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Concurrent;5using System.Collections.Generic;6using System.Diagnostics;7using System.Diagnostics.CodeAnalysis;8using System.Diagnostics.PerformanceData;9using System.Globalization;10using System.Management.Automation.Tracing;11 12namespace System.Management.Automation.PerformanceData13{14 /// <summary>15 /// An abstract class that forms the base class for any Counter Set type.16 /// A Counter Set Instance is required to register a given performance counter category17 /// with PSPerfCountersMgr.18 /// </summary>19 public abstract class CounterSetInstanceBase : IDisposable20 {21 private readonly PowerShellTraceSource _tracer = PowerShellTraceSourceFactory.GetTraceSource();22 #region Protected Members23 24 /// <summary>25 /// An instance of counterSetRegistrarBase type encapsulates all the information26 /// about a counter set and its associated counters.27 /// </summary>28 [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")]29 protected CounterSetRegistrarBase _counterSetRegistrarBase;30 31 // NOTE: Check whether the following dictionaries need to be concurrent32 // because there would be only 1 thread creating the instance,33 // and that instance would then be shared by multiple threads for data access.34 // Those threads won't modify/manipulate the dictionary, but they would only access it.35 36 /// <summary>37 /// Dictionary mapping counter name to id.38 /// </summary>39 [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")]40 protected ConcurrentDictionary<string, int> _counterNameToIdMapping;41 /// <summary>42 /// Dictionary mapping counter id to counter type.43 /// </summary>44 [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")]45 protected ConcurrentDictionary<int, CounterType> _counterIdToTypeMapping;46 47 #region Constructors48 /// <summary>49 /// Constructor.50 /// </summary>51 protected CounterSetInstanceBase(CounterSetRegistrarBase counterSetRegistrarInst)52 {53 this._counterSetRegistrarBase = counterSetRegistrarInst;54 _counterNameToIdMapping = new ConcurrentDictionary<string, int>();55 _counterIdToTypeMapping = new ConcurrentDictionary<int, CounterType>();56 57 CounterInfo[] counterInfoArray = this._counterSetRegistrarBase.CounterInfoArray;58 59 for (int i = 0; i < counterInfoArray.Length; i++)60 {61 this._counterIdToTypeMapping.TryAdd(counterInfoArray[i].Id, counterInfoArray[i].Type);62 if (!string.IsNullOrWhiteSpace(counterInfoArray[i].Name))63 {64 this._counterNameToIdMapping.TryAdd(counterInfoArray[i].Name, counterInfoArray[i].Id);65 }66 }67 }68 69 #endregion70 71 /// <summary>72 /// Method that retrieves the target counter id.73 /// NOTE: If isNumerator is true, then input counter id is returned.74 /// But, if isNumerator is false, then a check is made on the input75 /// counter's type to ensure that denominator is indeed value for such a counter.76 /// </summary>77 protected bool RetrieveTargetCounterIdIfValid(int counterId, bool isNumerator, out int targetCounterId)78 {79 targetCounterId = counterId;80 if (isNumerator == false)81 {82 bool isDenominatorValid = false;83 CounterType counterType = this._counterIdToTypeMapping[counterId];84 switch (counterType)85 {86 case CounterType.MultiTimerPercentageActive:87 case CounterType.MultiTimerPercentageActive100Ns:88 case CounterType.MultiTimerPercentageNotActive:89 case CounterType.MultiTimerPercentageNotActive100Ns:90 case CounterType.RawFraction32:91 case CounterType.RawFraction64:92 case CounterType.SampleFraction:93 case CounterType.AverageCount64:94 case CounterType.AverageTimer32:95 isDenominatorValid = true;96 break;97 }98 99 if (isDenominatorValid == false)100 {101 InvalidOperationException invalidOperationException =102 new InvalidOperationException(103 string.Format(104 CultureInfo.InvariantCulture,105 "Denominator for update not valid for the given counter id {0}",106 counterId));107 _tracer.TraceException(invalidOperationException);108 return false;109 }110 111 targetCounterId = counterId + 1;112 }113 114 return true;115 }116 117 #endregion118 119 #region Public Methods120 121 /// <summary>122 /// If isNumerator is true, then updates the numerator component123 /// of target counter 'counterId' by a value given by 'stepAmount'.124 /// Otherwise, updates the denominator component by 'stepAmount'.125 /// </summary>126 public abstract bool UpdateCounterByValue(127 int counterId,128 long stepAmount,129 bool isNumerator);130 131 /// <summary>132 /// If isNumerator is true, then updates the numerator component133 /// of target counter 'counterName' by a value given by 'stepAmount'.134 /// Otherwise, updates the denominator component by 'stepAmount'.135 /// </summary>136 public abstract bool UpdateCounterByValue(137 string counterName,138 long stepAmount,139 bool isNumerator);140 141 /// <summary>142 /// If isNumerator is true, then sets the numerator component of target143 /// counter 'counterId' to 'counterValue'.144 /// Otherwise, sets the denominator component to 'counterValue'.145 /// </summary>146 public abstract bool SetCounterValue(147 int counterId,148 long counterValue,149 bool isNumerator);150 151 /// <summary>152 /// If isNumerator is true, then sets the numerator component of target153 /// Counter 'counterName' to 'counterValue'.154 /// Otherwise, sets the denominator component to 'counterValue'.155 /// </summary>156 public abstract bool SetCounterValue(157 string counterName,158 long counterValue,159 bool isNumerator);160 161 /// <summary>162 /// This method retrieves the counter value associated with counter 'counterId'163 /// based on isNumerator parameter.164 /// </summary>165 public abstract bool GetCounterValue(int counterId, bool isNumerator, out long counterValue);166 167 /// <summary>168 /// This method retrieves the counter value associated with counter 'counterName'169 /// based on isNumerator parameter.170 /// </summary>171 public abstract bool GetCounterValue(string counterName, bool isNumerator, out long counterValue);172 173 /// <summary>174 /// An abstract method that will be implemented by the derived type175 /// so as to dispose the appropriate counter set instance.176 /// </summary>177 public abstract void Dispose();178 179 /*180 /// <summary>181 /// Resets the target counter 'counterId' to 0. If the given182 /// counter has both numerator and denominator components, then183 /// they both are set to 0.184 /// </summary>185 public bool ResetCounter(186 int counterId)187 {188 this.SetCounterValue(counterId, 0, true);189 this.SetCounterValue(counterId, 0, false);190 }191 192 /// <summary>193 /// Resets the target counter 'counterName' to 0. If the given194 /// counter has both numerator and denominator components, then195 /// they both are set to 0.196 /// </summary>197 public void ResetCounter(string counterName)198 {199 this.SetCounterValue(counterName, 0, true);200 this.SetCounterValue(counterName, 0, false);201 }202 */203 #endregion204 }205 206 /// <summary>207 /// PSCounterSetInstance is a thin wrapper208 /// on System.Diagnostics.PerformanceData.CounterSetInstance.209 /// </summary>210 public class PSCounterSetInstance : CounterSetInstanceBase211 {212 #region Private Members213 private bool _Disposed;214 private CounterSet _CounterSet;215 private CounterSetInstance _CounterSetInstance;216 private readonly PowerShellTraceSource _tracer = PowerShellTraceSourceFactory.GetTraceSource();217 218 #region Private Methods219 220 private void CreateCounterSetInstance()221 {222 _CounterSet =223 new CounterSet(224 base._counterSetRegistrarBase.ProviderId,225 base._counterSetRegistrarBase.CounterSetId,226 base._counterSetRegistrarBase.CounterSetInstType);227 228 // Add the counters to the counter set definition.229 foreach (CounterInfo counterInfo in base._counterSetRegistrarBase.CounterInfoArray)230 {231 if (counterInfo.Name == null)232 {233 _CounterSet.AddCounter(counterInfo.Id, counterInfo.Type);234 }235 else236 {237 _CounterSet.AddCounter(counterInfo.Id, counterInfo.Type, counterInfo.Name);238 }239 }240 241 string instanceName = PSPerfCountersMgr.Instance.GetCounterSetInstanceName();242 // Create an instance of the counter set (contains the counter data).243 _CounterSetInstance = _CounterSet.CreateCounterSetInstance(instanceName);244 }245 246 private void UpdateCounterByValue(CounterData TargetCounterData, long stepAmount)247 {248 Debug.Assert(TargetCounterData != null);249 if (stepAmount == -1)250 {251 TargetCounterData.Decrement();252 }253 else if (stepAmount == 1)254 {255 TargetCounterData.Increment();256 }257 else258 {259 TargetCounterData.IncrementBy(stepAmount);260 }261 }262 263 #endregion264 265 #endregion266 267 #region Constructors268 /// <summary>269 /// Constructor for creating an instance of PSCounterSetInstance.270 /// </summary>271 public PSCounterSetInstance(CounterSetRegistrarBase counterSetRegBaseObj)272 : base(counterSetRegBaseObj)273 {274 CreateCounterSetInstance();275 }276 277 #endregion278 279 #region Destructor280 281 /// <summary>282 /// This destructor will run only if the Dispose method283 /// does not get called.284 /// It gives the base class opportunity to finalize.285 /// </summary>286 ~PSCounterSetInstance()287 {288 Dispose(false);289 }290 291 #endregion292 293 #region Protected Methods294 /// <summary>295 /// Dispose(bool disposing) executes in two distinct scenarios.296 /// If disposing equals true, the method has been called directly297 /// or indirectly by a user's code. Managed and unmanaged resources298 /// can be disposed.299 /// If disposing equals false, the method has been called by the300 /// runtime from inside the finalizer and you should not reference301 /// other objects. Only unmanaged resources can be disposed.302 /// </summary>303 protected virtual void Dispose(bool disposing)304 {305 // Check to see if Dispose has already been called.306 if (!_Disposed)307 {308 // If disposing equals true, dispose all managed309 // and unmanaged resources.310 if (disposing)311 {312 // Dispose managed resources.313 _CounterSetInstance.Dispose();314 _CounterSet.Dispose();315 }316 // Note disposing has been done.317 _Disposed = true;318 }319 }320 321 #endregion322 323 #region IDisposable Overrides324 /// <summary>325 /// Dispose Method implementation for IDisposable interface.326 /// </summary>327 public override void Dispose()328 {329 this.Dispose(true);330 // This object will be cleaned up by the Dispose method.331 // Therefore, you should call GC.SuppressFinalize to332 // take this object off the finalization queue333 // and prevent finalization code for this object334 // from executing a second time.335 GC.SuppressFinalize(this);336 }337 338 #endregion339 340 #region CounterSetInstanceBase Overrides341 342 #region Public Methods343 344 /// <summary>345 /// If isNumerator is true, then updates the numerator component346 /// of target counter 'counterId' by a value given by 'stepAmount'.347 /// Otherwise, updates the denominator component by 'stepAmount'.348 /// </summary>349 public override bool UpdateCounterByValue(int counterId, long stepAmount, bool isNumerator)350 {351 if (_Disposed)352 {353 ObjectDisposedException objectDisposedException =354 new ObjectDisposedException("PSCounterSetInstance");355 _tracer.TraceException(objectDisposedException);356 return false;357 }358 359 int targetCounterId;360 if (base.RetrieveTargetCounterIdIfValid(counterId, isNumerator, out targetCounterId))361 {362 CounterData targetCounterData = _CounterSetInstance.Counters[targetCounterId];363 if (targetCounterData != null)364 {365 this.UpdateCounterByValue(targetCounterData, stepAmount);366 return true;367 }368 else369 {370 InvalidOperationException invalidOperationException =371 new InvalidOperationException(372 string.Format(373 CultureInfo.InvariantCulture,374 "Lookup for counter corresponding to counter id {0} failed",375 counterId));376 _tracer.TraceException(invalidOperationException);377 return false;378 }379 }380 else381 {382 return false;383 }384 }385 /// <summary>386 /// If isNumerator is true, then updates the numerator component387 /// of target counter 'counterName' by a value given by 'stepAmount'.388 /// Otherwise, updates the denominator component by 'stepAmount'.389 /// </summary>390 public override bool UpdateCounterByValue(string counterName, long stepAmount, bool isNumerator)391 {392 if (_Disposed)393 {394 ObjectDisposedException objectDisposedException =395 new ObjectDisposedException("PSCounterSetInstance");396 _tracer.TraceException(objectDisposedException);397 return false;398 }399 // retrieve counter id associated with the counter name400 if (counterName == null)401 {402 ArgumentNullException argNullException = new ArgumentNullException(nameof(counterName));403 _tracer.TraceException(argNullException);404 return false;405 }406 407 try408 {409 int targetCounterId = this._counterNameToIdMapping[counterName];410 return this.UpdateCounterByValue(targetCounterId, stepAmount, isNumerator);411 }412 catch (KeyNotFoundException)413 {414 InvalidOperationException invalidOperationException =415 new InvalidOperationException(416 string.Format(417 CultureInfo.InvariantCulture,418 "Lookup for counter corresponding to counter name {0} failed",419 counterName));420 _tracer.TraceException(invalidOperationException);421 return false;422 }423 }424 425 /// <summary>426 /// If isNumerator is true, then sets the numerator component427 /// of target counter 'counterId' to 'counterValue'.428 /// Otherwise, sets the denominator component to 'counterValue'.429 /// </summary>430 public override bool SetCounterValue(int counterId, long counterValue, bool isNumerator)431 {432 if (_Disposed)433 {434 ObjectDisposedException objectDisposedException =435 new ObjectDisposedException("PSCounterSetInstance");436 _tracer.TraceException(objectDisposedException);437 return false;438 }439 440 int targetCounterId;441 if (base.RetrieveTargetCounterIdIfValid(counterId, isNumerator, out targetCounterId))442 {443 CounterData targetCounterData = _CounterSetInstance.Counters[targetCounterId];444 445 if (targetCounterData != null)446 {447 targetCounterData.Value = counterValue;448 return true;449 }450 else451 {452 InvalidOperationException invalidOperationException =453 new InvalidOperationException(454 string.Format(455 CultureInfo.InvariantCulture,456 "Lookup for counter corresponding to counter id {0} failed",457 counterId));458 _tracer.TraceException(invalidOperationException);459 return false;460 }461 }462 else463 {464 return false;465 }466 }467 468 /// <summary>469 /// If isNumerator is true, then updates the numerator component470 /// of target counter 'counterName' by a value given by 'counterValue'.471 /// Otherwise, sets the denominator component to 'counterValue'.472 /// </summary>473 public override bool SetCounterValue(string counterName, long counterValue, bool isNumerator)474 {475 if (_Disposed)476 {477 ObjectDisposedException objectDisposedException =478 new ObjectDisposedException("PSCounterSetInstance");479 _tracer.TraceException(objectDisposedException);480 return false;481 }482 483 // retrieve counter id associated with the counter name484 if (counterName == null)485 {486 ArgumentNullException argNullException = new ArgumentNullException(nameof(counterName));487 _tracer.TraceException(argNullException);488 return false;489 }490 491 try492 {493 int targetCounterId = this._counterNameToIdMapping[counterName];494 return this.SetCounterValue(targetCounterId, counterValue, isNumerator);495 }496 catch (KeyNotFoundException)497 {498 InvalidOperationException invalidOperationException =499 new InvalidOperationException(500 string.Format(501 CultureInfo.InvariantCulture,502 "Lookup for counter corresponding to counter name {0} failed",503 counterName));504 _tracer.TraceException(invalidOperationException);505 return false;506 }507 }508 509 /// <summary>510 /// This method retrieves the counter value associated with counter 'counterId'511 /// based on isNumerator parameter.512 /// </summary>513 public override bool GetCounterValue(int counterId, bool isNumerator, out long counterValue)514 {515 counterValue = -1;516 if (_Disposed)517 {518 ObjectDisposedException objectDisposedException =519 new ObjectDisposedException("PSCounterSetInstance");520 _tracer.TraceException(objectDisposedException);521 return false;522 }523 524 int targetCounterId;525 if (base.RetrieveTargetCounterIdIfValid(counterId, isNumerator, out targetCounterId))526 {527 CounterData targetCounterData = _CounterSetInstance.Counters[targetCounterId];528 529 if (targetCounterData != null)530 {531 counterValue = targetCounterData.Value;532 return true;533 }534 else535 {536 InvalidOperationException invalidOperationException =537 new InvalidOperationException(538 string.Format(539 CultureInfo.InvariantCulture,540 "Lookup for counter corresponding to counter id {0} failed",541 counterId));542 _tracer.TraceException(invalidOperationException);543 return false;544 }545 }546 else547 {548 return false;549 }550 }551 552 /// <summary>553 /// This method retrieves the counter value associated with counter 'counterName'554 /// based on isNumerator parameter.555 /// </summary>556 public override bool GetCounterValue(string counterName, bool isNumerator, out long counterValue)557 {558 counterValue = -1;559 if (_Disposed)560 {561 ObjectDisposedException objectDisposedException =562 new ObjectDisposedException("PSCounterSetInstance");563 _tracer.TraceException(objectDisposedException);564 return false;565 }566 567 // retrieve counter id associated with the counter name568 if (counterName == null)569 {570 ArgumentNullException argNullException = new ArgumentNullException(nameof(counterName));571 _tracer.TraceException(argNullException);572 return false;573 }574 575 try576 {577 int targetCounterId = this._counterNameToIdMapping[counterName];578 return this.GetCounterValue(targetCounterId, isNumerator, out counterValue);579 }580 catch (KeyNotFoundException)581 {582 InvalidOperationException invalidOperationException =583 new InvalidOperationException(584 string.Format(585 CultureInfo.InvariantCulture,586 "Lookup for counter corresponding to counter name {0} failed",587 counterName));588 _tracer.TraceException(invalidOperationException);589 return false;590 }591 }592 593 #endregion594 #endregion595 }596}597 