1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
// <copyright file="PerfCounters.cs" company="Microsoft">
// Copyright (c) 2009 Microsoft Corporation. All rights reserved.
// </copyright>
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.Caching.Hosting;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
namespace System.Runtime.Caching {
internal sealed class PerfCounters : IDisposable {
private const string PERF_COUNTER_CATEGORY = ".NET Memory Cache 4.0";
private const string CACHE_ENTRIES = "Cache Entries";
private const string CACHE_HITS = "Cache Hits";
private const string CACHE_HIT_RATIO = "Cache Hit Ratio";
private const string CACHE_HIT_RATIO_BASE = "Cache Hit Ratio Base";
private const string CACHE_MISSES = "Cache Misses";
private const string CACHE_TRIMS = "Cache Trims";
private const string CACHE_TURNOVER = "Cache Turnover Rate";
private const int NUM_COUNTERS = 7;
private static string s_appId;
private PerformanceCounter[] _counters;
private long[] _counterValues;
[SecuritySafeCritical]
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
[SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "Grandfathered suppression from original caching code checkin")]
private static void EnsureAppIdInited() {
if (s_appId == null) {
IApplicationIdentifier ai = null;
IServiceProvider host = ObjectCache.Host;
if (host != null) {
ai = host.GetService(typeof(IApplicationIdentifier)) as IApplicationIdentifier;
}
// if the host has an identifier, use it
string appId = (ai != null) ? ai.GetApplicationId() : null;
// otherwise, use the process name wihtout file extension
#if !MONO
if (String.IsNullOrEmpty(appId)) {
StringBuilder sb = new StringBuilder(512);
if (UnsafeNativeMethods.GetModuleFileName(IntPtr.Zero, sb, 512) != 0) {
appId = Path.GetFileNameWithoutExtension(sb.ToString());
}
}
#endif
// if all else fails, use AppDomain.FriendlyName
if (String.IsNullOrEmpty(appId)) {
appId = AppDomain.CurrentDomain.FriendlyName;
}
Interlocked.CompareExchange(ref s_appId, appId, null);
}
}
private void InitDisposableMembers(string cacheName) {
bool dispose = true;
try {
StringBuilder sb = (s_appId != null) ? new StringBuilder(s_appId + ":" + cacheName) : new StringBuilder(cacheName);
for (int i = 0; i < sb.Length; i++) {
switch (sb[i]) {
case '(':
sb[i] = '[';
break;
case ')':
sb[i] = ']';
break;
case '/':
case '\\':
case '#':
sb[i] = '_';
break;
}
}
string instanceName = sb.ToString();
_counters = new PerformanceCounter[NUM_COUNTERS];
_counterValues = new long[NUM_COUNTERS];
_counters[(int)PerfCounterName.Entries] = new PerformanceCounter(PERF_COUNTER_CATEGORY, CACHE_ENTRIES, instanceName, false);
_counters[(int)PerfCounterName.Hits] = new PerformanceCounter(PERF_COUNTER_CATEGORY, CACHE_HITS, instanceName, false);
_counters[(int)PerfCounterName.HitRatio] = new PerformanceCounter(PERF_COUNTER_CATEGORY, CACHE_HIT_RATIO, instanceName, false);
_counters[(int)PerfCounterName.HitRatioBase] = new PerformanceCounter(PERF_COUNTER_CATEGORY, CACHE_HIT_RATIO_BASE, instanceName, false);
_counters[(int)PerfCounterName.Misses] = new PerformanceCounter(PERF_COUNTER_CATEGORY, CACHE_MISSES, instanceName, false);
_counters[(int)PerfCounterName.Trims] = new PerformanceCounter(PERF_COUNTER_CATEGORY, CACHE_TRIMS, instanceName, false);
_counters[(int)PerfCounterName.Turnover] = new PerformanceCounter(PERF_COUNTER_CATEGORY, CACHE_TURNOVER, instanceName, false);
dispose = false;
}
finally {
if (dispose) {
Dispose();
}
}
}
private PerfCounters() {
// hide default ctor
}
internal PerfCounters(string cacheName) {
if (cacheName == null) {
throw new ArgumentNullException("cacheName");
}
EnsureAppIdInited();
InitDisposableMembers(cacheName);
}
internal void Decrement(PerfCounterName name) {
int idx = (int) name;
PerformanceCounter counter = _counters[idx];
counter.Decrement();
Interlocked.Decrement(ref _counterValues[idx]);
}
internal void Increment(PerfCounterName name) {
int idx = (int) name;
PerformanceCounter counter = _counters[idx];
counter.Increment();
Interlocked.Increment(ref _counterValues[idx]);
}
internal void IncrementBy(PerfCounterName name, long value) {
int idx = (int) name;
PerformanceCounter counter = _counters[idx];
counter.IncrementBy(value);
Interlocked.Add(ref _counterValues[idx], value);
}
public void Dispose() {
PerformanceCounter[] counters = _counters;
// ensure this only happens once
if (counters != null && Interlocked.CompareExchange(ref _counters, null, counters) == counters) {
for (int i = 0; i < NUM_COUNTERS; i++) {
PerformanceCounter counter = counters[i];
if (counter != null) {
// decrement counter by its current value, to zero it out for this instance of the named cache (see Dev10 Bug 680819)
long value = Interlocked.Exchange(ref _counterValues[i], 0);
if (value != 0) {
counter.IncrementBy(-value);
}
counter.Dispose();
}
}
}
// Don't need to call GC.SuppressFinalize(this) for sealed types without finalizers.
}
}
}
|