Welcome to mirror list, hosted at ThFree Co, Russian Federation.

PerfCounters.cs « Caching « System « System.Runtime.Caching « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 1b481f800f7ea64739b9d2f130c538316f88ca77 (plain)
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.
        }
    }
}