Evict older half of items in the cache by removing items from the end of the list, don't waste cycles computing timestamps.
This commit is contained in:
parent
b727538162
commit
bc0f5dbfc7
6 changed files with 18 additions and 456 deletions
|
@ -44,7 +44,6 @@ struct async_nif_req_entry {
|
||||||
void *args;
|
void *args;
|
||||||
void (*fn_work)(ErlNifEnv*, ERL_NIF_TERM, ErlNifPid*, unsigned int, void *);
|
void (*fn_work)(ErlNifEnv*, ERL_NIF_TERM, ErlNifPid*, unsigned int, void *);
|
||||||
void (*fn_post)(void *);
|
void (*fn_post)(void *);
|
||||||
uint64_t submitted;
|
|
||||||
STAILQ_ENTRY(async_nif_req_entry) entries;
|
STAILQ_ENTRY(async_nif_req_entry) entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -109,7 +108,6 @@ struct async_nif_state {
|
||||||
enif_make_atom(env, "shutdown")); \
|
enif_make_atom(env, "shutdown")); \
|
||||||
} \
|
} \
|
||||||
req = async_nif_reuse_req(async_nif); \
|
req = async_nif_reuse_req(async_nif); \
|
||||||
req->submitted = ts(ns); \
|
|
||||||
if (!req) { \
|
if (!req) { \
|
||||||
return enif_make_tuple2(env, enif_make_atom(env, "error"), \
|
return enif_make_tuple2(env, enif_make_atom(env, "error"), \
|
||||||
enif_make_atom(env, "eagain")); \
|
enif_make_atom(env, "eagain")); \
|
||||||
|
@ -415,7 +413,6 @@ async_nif_worker_fn(void *arg)
|
||||||
|
|
||||||
/* Clean up req for reuse. */
|
/* Clean up req for reuse. */
|
||||||
req->ref = 0;
|
req->ref = 0;
|
||||||
req->submitted = 0;
|
|
||||||
req->fn_work = 0;
|
req->fn_work = 0;
|
||||||
req->fn_post = 0;
|
req->fn_post = 0;
|
||||||
enif_free(req->args);
|
enif_free(req->args);
|
||||||
|
|
123
c_src/duration.h
123
c_src/duration.h
|
@ -1,123 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2013, all rights reserved by Gregory Burd <greg@burd.me>
|
|
||||||
*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public License,
|
|
||||||
* version 2 (MPLv2). If a copy of the MPL was not distributed with this file,
|
|
||||||
* you can obtain one at: http://mozilla.org/MPL/2.0/
|
|
||||||
*
|
|
||||||
* NOTES:
|
|
||||||
* - on some platforms this will require -lrt
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/timeb.h>
|
|
||||||
|
|
||||||
#ifdef __MACH__
|
|
||||||
#include <mach/clock.h>
|
|
||||||
#include <mach/mach.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static inline void current_utc_time(struct timespec *ts)
|
|
||||||
{
|
|
||||||
#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
|
|
||||||
clock_serv_t cclock;
|
|
||||||
mach_timespec_t mts;
|
|
||||||
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
|
|
||||||
clock_get_time(cclock, &mts);
|
|
||||||
mach_port_deallocate(mach_task_self(), cclock);
|
|
||||||
ts->tv_sec = mts.tv_sec;
|
|
||||||
ts->tv_nsec = mts.tv_nsec;
|
|
||||||
#else
|
|
||||||
clock_gettime(CLOCK_REALTIME, ts);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef enum { ns = 0, mcs, ms, s } time_scale;
|
|
||||||
struct scale_time {
|
|
||||||
const char *abbreviation;
|
|
||||||
const char *name;
|
|
||||||
uint64_t mul, div, overhead, ticks_per;
|
|
||||||
};
|
|
||||||
static const struct scale_time scale[] = {
|
|
||||||
{ "ns", "nanosecond", 1000000000LL, 1LL, 10, 2300000000000LL },
|
|
||||||
{ "μs", "microsecond", 1000000LL, 1000LL, 10, 2300000000LL },
|
|
||||||
{ "ms", "millisecond", 1000LL, 1000000LL, 10, 2300000LL },
|
|
||||||
{ "sec", "second", 1LL, 1000000000LL, 10, 2300LL } };
|
|
||||||
|
|
||||||
static uint64_t ts(time_scale unit)
|
|
||||||
{
|
|
||||||
struct timespec ts;
|
|
||||||
current_utc_time(&ts);
|
|
||||||
return (((uint64_t)ts.tv_sec * scale[unit].mul) +
|
|
||||||
((uint64_t)ts.tv_nsec / scale[unit].div));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* cpu_clock_ticks()
|
|
||||||
*
|
|
||||||
* A measure provided by Intel x86 CPUs which provides the number of cycles
|
|
||||||
* (aka "ticks") executed as a counter using the RDTSC instruction.
|
|
||||||
*/
|
|
||||||
static inline uint64_t cpu_clock_ticks()
|
|
||||||
{
|
|
||||||
uint32_t lo, hi;
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"XORL %%eax, %%eax\n" /* Flush the pipeline */
|
|
||||||
"CPUID\n"
|
|
||||||
"RDTSC\n" /* Get RDTSC counter in edx:eax */
|
|
||||||
: "=a" (lo), "=d" (hi)
|
|
||||||
:
|
|
||||||
: "%ebx", "%ecx" );
|
|
||||||
return (uint64_t)hi << 32 | lo;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* cpu_clock_ticks()
|
|
||||||
*
|
|
||||||
* An approximation of elapsed [ns, mcs, ms, s] from CPU clock ticks.
|
|
||||||
*/
|
|
||||||
static uint64_t elapsed_cpu_clock_ticks(uint64_t start, time_scale unit)
|
|
||||||
{
|
|
||||||
return (cpu_clock_ticks() - start - scale[unit].overhead) * scale[unit].ticks_per;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint64_t then;
|
|
||||||
time_scale unit;
|
|
||||||
} duration_t;
|
|
||||||
|
|
||||||
static inline uint64_t elapsed(duration_t *d)
|
|
||||||
{
|
|
||||||
uint64_t now = ts(d->unit);
|
|
||||||
uint64_t elapsed = now - d->then;
|
|
||||||
d->then = now;
|
|
||||||
return elapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DURATION(name, resolution) duration_t name = \
|
|
||||||
{ts(resolution), resolution}
|
|
||||||
|
|
||||||
#define ELAPSED_DURING(result, resolution, block) \
|
|
||||||
do { \
|
|
||||||
DURATION(__x, resolution); \
|
|
||||||
do block while(0); \
|
|
||||||
*result = elapsed(&__x); \
|
|
||||||
} while(0);
|
|
||||||
|
|
||||||
#define CYCLES_DURING(result, block) \
|
|
||||||
do { \
|
|
||||||
uint64_t __begin = cpu_clock_ticks(); \
|
|
||||||
do block while(0); \
|
|
||||||
*result = cpu_clock_ticks() - __begin; \
|
|
||||||
} while(0);
|
|
|
@ -33,6 +33,17 @@
|
||||||
#ifndef _DB_QUEUE_H_
|
#ifndef _DB_QUEUE_H_
|
||||||
#define _DB_QUEUE_H_
|
#define _DB_QUEUE_H_
|
||||||
|
|
||||||
|
#ifndef __offsetof
|
||||||
|
#define __offsetof(st, m) \
|
||||||
|
((size_t) ( (char *)&((st *)0)->m - (char *)0 ))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __containerof
|
||||||
|
#define __containerof(ptr, type, member) ({ \
|
||||||
|
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||||
|
(type *)( (char *)__mptr - __offsetof(type,member) );})
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
240
c_src/stats.c
240
c_src/stats.c
|
@ -1,240 +0,0 @@
|
||||||
/*
|
|
||||||
* stats:
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 Basho Technologies, Inc. All Rights Reserved.
|
|
||||||
* Author: Gregory Burd <greg@basho.com> <greg@burd.me>
|
|
||||||
*
|
|
||||||
* This file is provided to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file
|
|
||||||
* except in compliance with the License. You may obtain
|
|
||||||
* a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#include "erl_nif.h"
|
|
||||||
#include "erl_driver.h"
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "duration.h"
|
|
||||||
#include "stats.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the log2 of 64bit unsigned integers.
|
|
||||||
*/
|
|
||||||
#ifdef __GCC__
|
|
||||||
#define LOG2(X) ((unsigned) ((8 * (sizeof(uint64_t) - 1)) - __builtin_clzll((X))))
|
|
||||||
#else
|
|
||||||
static unsigned int __log2_64(uint64_t x) {
|
|
||||||
static const int tab64[64] = {
|
|
||||||
63, 0, 58, 1, 59, 47, 53, 2,
|
|
||||||
60, 39, 48, 27, 54, 33, 42, 3,
|
|
||||||
61, 51, 37, 40, 49, 18, 28, 20,
|
|
||||||
55, 30, 34, 11, 43, 14, 22, 4,
|
|
||||||
62, 57, 46, 52, 38, 26, 32, 41,
|
|
||||||
50, 36, 17, 19, 29, 10, 13, 21,
|
|
||||||
56, 45, 25, 31, 35, 16, 9, 12,
|
|
||||||
44, 24, 15, 8, 23, 7, 6, 5};
|
|
||||||
if (x == 0) return 0;
|
|
||||||
uint64_t v = x;
|
|
||||||
v |= v >> 1;
|
|
||||||
v |= v >> 2;
|
|
||||||
v |= v >> 4;
|
|
||||||
v |= v >> 8;
|
|
||||||
v |= v >> 16;
|
|
||||||
v |= v >> 32;
|
|
||||||
return tab64[((uint64_t)((v - (v >> 1)) * 0x07EDD5E59A4E28C2)) >> 58];
|
|
||||||
}
|
|
||||||
#define LOG2(X) __log2_64(X)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
double
|
|
||||||
__stat_mean(struct stat *s)
|
|
||||||
{
|
|
||||||
uint32_t t, h;
|
|
||||||
double mean;
|
|
||||||
|
|
||||||
if (!s)
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
t = s->h;
|
|
||||||
h = (s->h + 1) % s->num_samples;
|
|
||||||
mean = 0;
|
|
||||||
|
|
||||||
while (h != t) {
|
|
||||||
mean += s->samples[h];
|
|
||||||
h = (h + 1) % s->num_samples;
|
|
||||||
}
|
|
||||||
if (mean > 0)
|
|
||||||
mean /= (s->n < s->num_samples ? (double)s->n : (double)s->num_samples);
|
|
||||||
return mean;
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
__stat_mean_log2(struct stat *s)
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
double mean = 0.0;
|
|
||||||
|
|
||||||
if (!s)
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
for (i = 0; i < 64; i++)
|
|
||||||
mean += (s->histogram[i] * i);
|
|
||||||
if (mean > 0)
|
|
||||||
mean /= (s->n < s->num_samples ? s->n : s->num_samples);
|
|
||||||
return mean;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t
|
|
||||||
__stat_tick(struct stat *s)
|
|
||||||
{
|
|
||||||
uint64_t t;
|
|
||||||
|
|
||||||
if (!s)
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
t = ts(s->d.unit);
|
|
||||||
s->d.then = t;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
__stat_reset(struct stat *s)
|
|
||||||
{
|
|
||||||
if (!s)
|
|
||||||
return;
|
|
||||||
|
|
||||||
s->h = 0;
|
|
||||||
s->d.unit = ns;
|
|
||||||
s->d.then = 0;
|
|
||||||
memset(s->histogram, 0, sizeof(uint64_t) * 64);
|
|
||||||
memset(s->samples, 0, sizeof(uint64_t) * s->num_samples);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
__stat_add(struct stat *s, uint64_t elapsed)
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
if (s->n == s->num_samples) {
|
|
||||||
s->mean = (s->mean + __stat_mean(s)) / 2.0;
|
|
||||||
if (s->n >= 4294967295) {
|
|
||||||
__stat_reset(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i = s->h;
|
|
||||||
s->h = (s->h + 1) % s->num_samples;
|
|
||||||
s->samples[i] = elapsed;
|
|
||||||
if (elapsed != 0 && elapsed < s->min)
|
|
||||||
s->min = elapsed;
|
|
||||||
if (elapsed > s->max)
|
|
||||||
s->max = elapsed;
|
|
||||||
s->histogram[LOG2(elapsed)]++;
|
|
||||||
s->n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
__stat_tock(struct stat *s)
|
|
||||||
{
|
|
||||||
if (s)
|
|
||||||
__stat_add(s, ts(s->d.unit));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
__stat_print_histogram(struct stat *s, const char *mod)
|
|
||||||
{
|
|
||||||
uint8_t logs[64];
|
|
||||||
uint8_t i, j, max_log = 0;
|
|
||||||
double m;
|
|
||||||
|
|
||||||
if (!s)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m = (s->mean + __stat_mean(s) / 2.0);
|
|
||||||
|
|
||||||
fprintf(stderr, "%s:async_nif request latency histogram:\n", mod);
|
|
||||||
for (i = 0; i < 64; i++) {
|
|
||||||
logs[i] = LOG2(s->histogram[i]);
|
|
||||||
if (logs[i] > max_log)
|
|
||||||
max_log = logs[i];
|
|
||||||
}
|
|
||||||
for (i = max_log; i > 0; i--) {
|
|
||||||
if (!(i % 10))
|
|
||||||
fprintf(stderr, "2^%2d ", i);
|
|
||||||
else
|
|
||||||
fprintf(stderr, " ");
|
|
||||||
for(j = 0; j < 64; j++)
|
|
||||||
fprintf(stderr, logs[j] >= i ? "•" : " ");
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
if (max_log == 0) {
|
|
||||||
fprintf(stderr, "[empty]\n");
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, " ns μs ms s ks\n");
|
|
||||||
fprintf(stderr, "min: ");
|
|
||||||
if (s->min < 1000)
|
|
||||||
fprintf(stderr, "%llu (ns)", PRIuint64(s->min));
|
|
||||||
else if (s->min < 1000000)
|
|
||||||
fprintf(stderr, "%.2f (μs)", s->min / 1000.0);
|
|
||||||
else if (s->min < 1000000000)
|
|
||||||
fprintf(stderr, "%.2f (ms)", s->min / 1000000.0);
|
|
||||||
else if (s->min < 1000000000000)
|
|
||||||
fprintf(stderr, "%.2f (s)", s->min / 1000000000.0);
|
|
||||||
fprintf(stderr, " max: ");
|
|
||||||
if (s->max < 1000)
|
|
||||||
fprintf(stderr, "%llu (ns)", PRIuint64(s->max));
|
|
||||||
else if (s->max < 1000000)
|
|
||||||
fprintf(stderr, "%.2f (μs)", s->max / 1000.0);
|
|
||||||
else if (s->max < 1000000000)
|
|
||||||
fprintf(stderr, "%.2f (ms)", s->max / 1000000.0);
|
|
||||||
else if (s->max < 1000000000000)
|
|
||||||
fprintf(stderr, "%.2f (s)", s->max / 1000000000.0);
|
|
||||||
fprintf(stderr, " mean: ");
|
|
||||||
if (m < 1000)
|
|
||||||
fprintf(stderr, "%.2f (ns)", m);
|
|
||||||
else if (m < 1000000)
|
|
||||||
fprintf(stderr, "%.2f (μs)", m / 1000.0);
|
|
||||||
else if (m < 1000000000)
|
|
||||||
fprintf(stderr, "%.2f (ms)", m / 1000000.0);
|
|
||||||
else if (m < 1000000000000)
|
|
||||||
fprintf(stderr, "%.2f (s)", m / 1000000000.0);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
fflush(stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
__stat_free(struct stat *s)
|
|
||||||
{
|
|
||||||
if (!s)
|
|
||||||
return;
|
|
||||||
|
|
||||||
enif_free(s->samples);
|
|
||||||
enif_free(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct stat *
|
|
||||||
__stat_init(uint32_t n)
|
|
||||||
{
|
|
||||||
struct stat *s = enif_alloc(sizeof(struct stat) + (sizeof(uint64_t) * n));
|
|
||||||
if (!s)
|
|
||||||
return NULL;
|
|
||||||
memset(s, 0, sizeof(struct stat) + (sizeof(uint64_t) * n));
|
|
||||||
s->min = ~0;
|
|
||||||
s->max = 0;
|
|
||||||
s->mean = 0.0;
|
|
||||||
s->h = 0;
|
|
||||||
s->num_samples = n;
|
|
||||||
s->d.unit = ns;
|
|
||||||
return s;
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* stats:
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 Basho Technologies, Inc. All Rights Reserved.
|
|
||||||
* Author: Gregory Burd <greg@basho.com> <greg@burd.me>
|
|
||||||
*
|
|
||||||
* This file is provided to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file
|
|
||||||
* except in compliance with the License. You may obtain
|
|
||||||
* a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __STATS_H__
|
|
||||||
#define __STATS_H__
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define STAT_DEF(name) struct stat *name ## _stat;
|
|
||||||
|
|
||||||
struct stat {
|
|
||||||
duration_t d;
|
|
||||||
uint32_t h, n, num_samples;
|
|
||||||
uint64_t min, max;
|
|
||||||
double mean;
|
|
||||||
uint64_t histogram[64];
|
|
||||||
uint64_t samples[];
|
|
||||||
};
|
|
||||||
|
|
||||||
extern double __stat_mean(struct stat *s);
|
|
||||||
extern double __stat_mean_log2(struct stat *s);
|
|
||||||
extern uint64_t __stat_tick(struct stat *s);
|
|
||||||
extern void __stat_add(struct stat *s, uint64_t d);
|
|
||||||
extern void __stat_reset(struct stat *s);
|
|
||||||
extern void __stat_tock(struct stat *s);
|
|
||||||
extern void __stat_print_histogram(struct stat *s, const char *mod);
|
|
||||||
extern void __stat_free(struct stat *s);
|
|
||||||
extern struct stat *__stat_init(uint32_t n);
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // __STATS_H__
|
|
|
@ -29,8 +29,6 @@
|
||||||
#include "wiredtiger.h"
|
#include "wiredtiger.h"
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "duration.h"
|
|
||||||
#include "stats.h"
|
|
||||||
#include "async_nif.h"
|
#include "async_nif.h"
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
#include "cas.h"
|
#include "cas.h"
|
||||||
|
@ -44,7 +42,6 @@ typedef char Uri[128];
|
||||||
|
|
||||||
struct wterl_ctx {
|
struct wterl_ctx {
|
||||||
STAILQ_ENTRY(wterl_ctx) entries;
|
STAILQ_ENTRY(wterl_ctx) entries;
|
||||||
uint64_t tstamp;
|
|
||||||
uint64_t sig;
|
uint64_t sig;
|
||||||
size_t sig_len;
|
size_t sig_len;
|
||||||
WT_SESSION *session;
|
WT_SESSION *session;
|
||||||
|
@ -64,8 +61,6 @@ typedef struct wterl_conn {
|
||||||
ErlNifMutex *cache_mutex;
|
ErlNifMutex *cache_mutex;
|
||||||
uint32_t cache_size;
|
uint32_t cache_size;
|
||||||
struct wterl_ctx *mru_ctx[ASYNC_NIF_MAX_WORKERS];
|
struct wterl_ctx *mru_ctx[ASYNC_NIF_MAX_WORKERS];
|
||||||
uint64_t histogram[64];
|
|
||||||
uint64_t histogram_count;
|
|
||||||
} WterlConnHandle;
|
} WterlConnHandle;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -193,47 +188,27 @@ static inline uint32_t __log2(uint64_t x) {
|
||||||
static int
|
static int
|
||||||
__ctx_cache_evict(WterlConnHandle *conn_handle)
|
__ctx_cache_evict(WterlConnHandle *conn_handle)
|
||||||
{
|
{
|
||||||
uint32_t mean, log, num_evicted, i;
|
uint32_t mean, num_evicted;
|
||||||
uint64_t now, elapsed;
|
struct wterl_ctx *c;
|
||||||
struct wterl_ctx *c, *n;
|
|
||||||
|
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
if (conn_handle->cache_size < MAX_CACHE_SIZE)
|
if (conn_handle->cache_size < MAX_CACHE_SIZE)
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
now = ts(ns);
|
mean = conn_handle->cache_size / 2;
|
||||||
|
if (mean < 2) return 0;
|
||||||
|
|
||||||
// Find the mean of the recorded times that items stayed in cache.
|
|
||||||
mean = 0;
|
|
||||||
for (i = 0; i < 64; i++)
|
|
||||||
mean += (conn_handle->histogram[i] * i);
|
|
||||||
if (mean > 0)
|
|
||||||
mean /= conn_handle->histogram_count;
|
|
||||||
|
|
||||||
// Clear out the histogram and hit/misses
|
|
||||||
memset(conn_handle->histogram, 0, sizeof(uint64_t) * 64);
|
|
||||||
conn_handle->histogram_count = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Evict anything older than the mean time in queue by removing those
|
|
||||||
* items from the lists stored in the tree.
|
|
||||||
*/
|
|
||||||
num_evicted = 0;
|
num_evicted = 0;
|
||||||
c = STAILQ_FIRST(&conn_handle->cache);
|
while (mean--) {
|
||||||
while (c != NULL) {
|
c = STAILQ_LAST(&conn_handle->cache, wterl_ctx, entries);
|
||||||
n = STAILQ_NEXT(c, entries);
|
if (c) {
|
||||||
elapsed = c->tstamp - now;
|
|
||||||
log = __log2(elapsed);
|
|
||||||
if (log > mean) {
|
|
||||||
STAILQ_REMOVE(&conn_handle->cache, c, wterl_ctx, entries);
|
STAILQ_REMOVE(&conn_handle->cache, c, wterl_ctx, entries);
|
||||||
DPRINTF("evicting: %llu", PRIuint64(c->sig));
|
|
||||||
if (c->session)
|
if (c->session)
|
||||||
c->session->close(c->session, NULL);
|
c->session->close(c->session, NULL);
|
||||||
enif_free(c);
|
enif_free(c);
|
||||||
num_evicted++;
|
num_evicted++;
|
||||||
}
|
}
|
||||||
c = n;
|
|
||||||
}
|
}
|
||||||
conn_handle->cache_size -= num_evicted;
|
conn_handle->cache_size -= num_evicted;
|
||||||
return num_evicted;
|
return num_evicted;
|
||||||
|
@ -259,8 +234,6 @@ __ctx_cache_find(WterlConnHandle *conn_handle, const uint64_t sig)
|
||||||
if (c->sig == sig) { // TODO: hash collisions *will* lead to SEGVs
|
if (c->sig == sig) { // TODO: hash collisions *will* lead to SEGVs
|
||||||
// cache hit:
|
// cache hit:
|
||||||
STAILQ_REMOVE(&conn_handle->cache, c, wterl_ctx, entries);
|
STAILQ_REMOVE(&conn_handle->cache, c, wterl_ctx, entries);
|
||||||
conn_handle->histogram[__log2(ts(ns) - c->tstamp)]++;
|
|
||||||
conn_handle->histogram_count++;
|
|
||||||
conn_handle->cache_size -= 1;
|
conn_handle->cache_size -= 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -282,7 +255,6 @@ __ctx_cache_add(WterlConnHandle *conn_handle, struct wterl_ctx *c)
|
||||||
{
|
{
|
||||||
enif_mutex_lock(conn_handle->cache_mutex);
|
enif_mutex_lock(conn_handle->cache_mutex);
|
||||||
__ctx_cache_evict(conn_handle);
|
__ctx_cache_evict(conn_handle);
|
||||||
c->tstamp = ts(ns);
|
|
||||||
STAILQ_INSERT_TAIL(&conn_handle->cache, c, entries);
|
STAILQ_INSERT_TAIL(&conn_handle->cache, c, entries);
|
||||||
conn_handle->cache_size += 1;
|
conn_handle->cache_size += 1;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
Loading…
Reference in a new issue