00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <config.h>
00022
00023 #include <string.h>
00024
00025 #include <isc/atomic.h>
00026 #include <isc/buffer.h>
00027 #include <isc/magic.h>
00028 #include <isc/mem.h>
00029 #include <isc/platform.h>
00030 #include <isc/print.h>
00031 #include <isc/rwlock.h>
00032 #include <isc/stats.h>
00033 #include <isc/util.h>
00034
00035 #define ISC_STATS_MAGIC ISC_MAGIC('S', 't', 'a', 't')
00036 #define ISC_STATS_VALID(x) ISC_MAGIC_VALID(x, ISC_STATS_MAGIC)
00037
00038 #ifndef ISC_STATS_USEMULTIFIELDS
00039 #if defined(ISC_RWLOCK_USEATOMIC) && defined(ISC_PLATFORM_HAVEXADD) && !defined(ISC_PLATFORM_HAVEXADDQ)
00040 #define ISC_STATS_USEMULTIFIELDS 1
00041 #else
00042 #define ISC_STATS_USEMULTIFIELDS 0
00043 #endif
00044 #endif
00045
00046 #if ISC_STATS_USEMULTIFIELDS
00047 typedef struct {
00048 isc_uint32_t hi;
00049 isc_uint32_t lo;
00050 } isc_stat_t;
00051 #else
00052 typedef isc_uint64_t isc_stat_t;
00053 #endif
00054
00055 struct isc_stats {
00056
00057 unsigned int magic;
00058 isc_mem_t *mctx;
00059 int ncounters;
00060
00061 isc_mutex_t lock;
00062 unsigned int references;
00063
00064
00065
00066
00067
00068 #ifdef ISC_RWLOCK_USEATOMIC
00069 isc_rwlock_t counterlock;
00070 #endif
00071 isc_stat_t *counters;
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 isc_uint64_t *copiedcounters;
00085 };
00086
00087 static isc_result_t
00088 create_stats(isc_mem_t *mctx, int ncounters, isc_stats_t **statsp) {
00089 isc_stats_t *stats;
00090 isc_result_t result = ISC_R_SUCCESS;
00091
00092 REQUIRE(statsp != NULL && *statsp == NULL);
00093
00094 stats = isc_mem_get(mctx, sizeof(*stats));
00095 if (stats == NULL)
00096 return (ISC_R_NOMEMORY);
00097
00098 result = isc_mutex_init(&stats->lock);
00099 if (result != ISC_R_SUCCESS)
00100 goto clean_stats;
00101
00102 stats->counters = isc_mem_get(mctx, sizeof(isc_stat_t) * ncounters);
00103 if (stats->counters == NULL) {
00104 result = ISC_R_NOMEMORY;
00105 goto clean_mutex;
00106 }
00107 stats->copiedcounters = isc_mem_get(mctx,
00108 sizeof(isc_uint64_t) * ncounters);
00109 if (stats->copiedcounters == NULL) {
00110 result = ISC_R_NOMEMORY;
00111 goto clean_counters;
00112 }
00113
00114 #ifdef ISC_RWLOCK_USEATOMIC
00115 result = isc_rwlock_init(&stats->counterlock, 0, 0);
00116 if (result != ISC_R_SUCCESS)
00117 goto clean_copiedcounters;
00118 #endif
00119
00120 stats->references = 1;
00121 memset(stats->counters, 0, sizeof(isc_stat_t) * ncounters);
00122 stats->mctx = NULL;
00123 isc_mem_attach(mctx, &stats->mctx);
00124 stats->ncounters = ncounters;
00125 stats->magic = ISC_STATS_MAGIC;
00126
00127 *statsp = stats;
00128
00129 return (result);
00130
00131 clean_counters:
00132 isc_mem_put(mctx, stats->counters, sizeof(isc_stat_t) * ncounters);
00133
00134 #ifdef ISC_RWLOCK_USEATOMIC
00135 clean_copiedcounters:
00136 isc_mem_put(mctx, stats->copiedcounters,
00137 sizeof(isc_stat_t) * ncounters);
00138 #endif
00139
00140 clean_mutex:
00141 DESTROYLOCK(&stats->lock);
00142
00143 clean_stats:
00144 isc_mem_put(mctx, stats, sizeof(*stats));
00145
00146 return (result);
00147 }
00148
00149 void
00150 isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp) {
00151 REQUIRE(ISC_STATS_VALID(stats));
00152 REQUIRE(statsp != NULL && *statsp == NULL);
00153
00154 LOCK(&stats->lock);
00155 stats->references++;
00156 UNLOCK(&stats->lock);
00157
00158 *statsp = stats;
00159 }
00160
00161 void
00162 isc_stats_detach(isc_stats_t **statsp) {
00163 isc_stats_t *stats;
00164
00165 REQUIRE(statsp != NULL && ISC_STATS_VALID(*statsp));
00166
00167 stats = *statsp;
00168 *statsp = NULL;
00169
00170 LOCK(&stats->lock);
00171 stats->references--;
00172
00173 if (stats->references == 0) {
00174 isc_mem_put(stats->mctx, stats->copiedcounters,
00175 sizeof(isc_stat_t) * stats->ncounters);
00176 isc_mem_put(stats->mctx, stats->counters,
00177 sizeof(isc_stat_t) * stats->ncounters);
00178 UNLOCK(&stats->lock);
00179 DESTROYLOCK(&stats->lock);
00180 #ifdef ISC_RWLOCK_USEATOMIC
00181 isc_rwlock_destroy(&stats->counterlock);
00182 #endif
00183 isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
00184 return;
00185 }
00186
00187 UNLOCK(&stats->lock);
00188 }
00189
00190 int
00191 isc_stats_ncounters(isc_stats_t *stats) {
00192 REQUIRE(ISC_STATS_VALID(stats));
00193
00194 return (stats->ncounters);
00195 }
00196
00197 static inline void
00198 incrementcounter(isc_stats_t *stats, int counter) {
00199 isc_int32_t prev;
00200
00201 #ifdef ISC_RWLOCK_USEATOMIC
00202
00203
00204
00205
00206
00207 isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_read);
00208 #endif
00209
00210 #if ISC_STATS_USEMULTIFIELDS
00211 prev = isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].lo, 1);
00212
00213
00214
00215
00216
00217
00218
00219
00220 if (prev == (isc_int32_t)0xffffffff)
00221 isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].hi, 1);
00222 #elif defined(ISC_PLATFORM_HAVEXADDQ)
00223 UNUSED(prev);
00224 isc_atomic_xaddq((isc_int64_t *)&stats->counters[counter], 1);
00225 #else
00226 UNUSED(prev);
00227 stats->counters[counter]++;
00228 #endif
00229
00230 #ifdef ISC_RWLOCK_USEATOMIC
00231 isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_read);
00232 #endif
00233 }
00234
00235 static inline void
00236 decrementcounter(isc_stats_t *stats, int counter) {
00237 isc_int32_t prev;
00238
00239 #ifdef ISC_RWLOCK_USEATOMIC
00240 isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_read);
00241 #endif
00242
00243 #if ISC_STATS_USEMULTIFIELDS
00244 prev = isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].lo, -1);
00245 if (prev == 0)
00246 isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].hi,
00247 -1);
00248 #elif defined(ISC_PLATFORM_HAVEXADDQ)
00249 UNUSED(prev);
00250 isc_atomic_xaddq((isc_int64_t *)&stats->counters[counter], -1);
00251 #else
00252 UNUSED(prev);
00253 stats->counters[counter]--;
00254 #endif
00255
00256 #ifdef ISC_RWLOCK_USEATOMIC
00257 isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_read);
00258 #endif
00259 }
00260
00261 static void
00262 copy_counters(isc_stats_t *stats) {
00263 int i;
00264
00265 #ifdef ISC_RWLOCK_USEATOMIC
00266
00267
00268
00269
00270 isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_write);
00271 #endif
00272
00273 #if ISC_STATS_USEMULTIFIELDS
00274 for (i = 0; i < stats->ncounters; i++) {
00275 stats->copiedcounters[i] =
00276 (isc_uint64_t)(stats->counters[i].hi) << 32 |
00277 stats->counters[i].lo;
00278 }
00279 #else
00280 UNUSED(i);
00281 memmove(stats->copiedcounters, stats->counters,
00282 stats->ncounters * sizeof(isc_stat_t));
00283 #endif
00284
00285 #ifdef ISC_RWLOCK_USEATOMIC
00286 isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_write);
00287 #endif
00288 }
00289
00290 isc_result_t
00291 isc_stats_create(isc_mem_t *mctx, isc_stats_t **statsp, int ncounters) {
00292 REQUIRE(statsp != NULL && *statsp == NULL);
00293
00294 return (create_stats(mctx, ncounters, statsp));
00295 }
00296
00297 void
00298 isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter) {
00299 REQUIRE(ISC_STATS_VALID(stats));
00300 REQUIRE(counter < stats->ncounters);
00301
00302 incrementcounter(stats, (int)counter);
00303 }
00304
00305 void
00306 isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter) {
00307 REQUIRE(ISC_STATS_VALID(stats));
00308 REQUIRE(counter < stats->ncounters);
00309
00310 decrementcounter(stats, (int)counter);
00311 }
00312
00313 void
00314 isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn,
00315 void *arg, unsigned int options)
00316 {
00317 int i;
00318
00319 REQUIRE(ISC_STATS_VALID(stats));
00320
00321 copy_counters(stats);
00322
00323 for (i = 0; i < stats->ncounters; i++) {
00324 if ((options & ISC_STATSDUMP_VERBOSE) == 0 &&
00325 stats->copiedcounters[i] == 0)
00326 continue;
00327 dump_fn((isc_statscounter_t)i, stats->copiedcounters[i], arg);
00328 }
00329 }
00330
00331 void
00332 isc_stats_set(isc_stats_t *stats, isc_uint64_t val,
00333 isc_statscounter_t counter)
00334 {
00335 REQUIRE(ISC_STATS_VALID(stats));
00336 REQUIRE(counter < stats->ncounters);
00337
00338 #ifdef ISC_RWLOCK_USEATOMIC
00339
00340
00341
00342
00343 isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_write);
00344 #endif
00345
00346 #if ISC_STATS_USEMULTIFIELDS
00347 stats->counters[counter].hi = (isc_uint32_t)((val >> 32) & 0xffffffff);
00348 stats->counters[counter].lo = (isc_uint32_t)(val & 0xffffffff);
00349 #else
00350 stats->counters[counter] = val;
00351 #endif
00352
00353 #ifdef ISC_RWLOCK_USEATOMIC
00354 isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_write);
00355 #endif
00356 }
00357