Commit d13c674d authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Add stats counters for VSM usage/overflows.

Various minor polish to VSM area.
parent 40c0fef6
......@@ -850,7 +850,7 @@ int SES_Schedule(struct sess *sp);
/* cache_shmlog.c */
extern struct VSC_C_main *VSC_C_main;
void VSL_Init(void);
void VSM_Init(void);
void *VSM_Alloc(unsigned size, const char *class, const char *type,
const char *ident);
void VSM_Free(void *ptr);
......
......@@ -103,7 +103,7 @@ child_main(void)
THR_SetName("cache-main");
VSL_Init(); /* First, LCK needs it. */
VSM_Init(); /* First, LCK needs it. */
LCK_Init(); /* Second, locking */
......
......@@ -38,6 +38,7 @@
#include "cache_backend.h" // For w->vbc
#include "vmb.h"
#include "vtim.h"
/* These cannot be struct lock, which depends on vsm/vsl working */
static pthread_mutex_t vsl_mtx;
......@@ -299,10 +300,26 @@ WSLB(struct worker *w, enum VSL_tag_e tag, const char *fmt, ...)
/*--------------------------------------------------------------------*/
static void *
vsm_cleaner(void *priv)
{
(void)priv;
THR_SetName("vsm_cleaner");
while (1) {
AZ(pthread_mutex_lock(&vsm_mtx));
VSM_common_cleaner(heritage.vsm, VSC_C_main);
AZ(pthread_mutex_unlock(&vsm_mtx));
VTIM_sleep(1.1);
}
}
/*--------------------------------------------------------------------*/
void
VSL_Init(void)
VSM_Init(void)
{
uint32_t *vsl_log_start;
pthread_t tp;
AZ(pthread_mutex_init(&vsl_mtx, NULL));
AZ(pthread_mutex_init(&vsm_mtx, NULL));
......@@ -328,6 +345,8 @@ VSL_Init(void)
// VSM_head->starttime = (intmax_t)VTIM_real();
memset(VSC_C_main, 0, sizeof *VSC_C_main);
// VSM_head->child_pid = getpid();
AZ(pthread_create(&tp, NULL, vsm_cleaner, NULL));
}
/*--------------------------------------------------------------------*/
......
......@@ -69,12 +69,14 @@ void mgt_child_inherit(int fd, const char *what);
/* vsm.c */
struct vsm_sc;
struct VSC_C_main;
struct vsm_sc *VSM_common_new(void *ptr, ssize_t len);
void *VSM_common_alloc(struct vsm_sc *sc, ssize_t size,
const char *class, const char *type, const char *ident);
void VSM_common_free(struct vsm_sc *sc, void *ptr);
void VSM_common_delete(struct vsm_sc **sc);
void VSM_common_copy(struct vsm_sc *to, const struct vsm_sc *from);
void VSM_common_cleaner(struct vsm_sc *sc, struct VSC_C_main *stats);
/*---------------------------------------------------------------------
* Generic power-2 rounding macros
......
......@@ -43,6 +43,7 @@
#include "common.h"
#include "vapi/vsm_int.h"
#include "vapi/vsc_int.h"
#include "vmb.h"
#include "vtim.h"
......@@ -69,6 +70,11 @@ struct vsm_sc {
VTAILQ_HEAD(,vsm_range) r_cooling;
VTAILQ_HEAD(,vsm_range) r_free;
VTAILQ_HEAD(,vsm_range) r_bogus;
uint64_t g_free;
uint64_t g_used;
uint64_t g_cooling;
uint64_t g_overflow;
uint64_t c_overflow;
};
/*--------------------------------------------------------------------
......@@ -148,9 +154,36 @@ VSM_common_new(void *p, ssize_t l)
vr->off = RUP2(sizeof(*sc->head), 16);
vr->len = RDN2(l - vr->off, 16);
VTAILQ_INSERT_TAIL(&sc->r_free, vr, list);
sc->g_free = vr->len;
return (sc);
}
/*--------------------------------------------------------------------
* Move from cooling list to free list
*/
void
VSM_common_cleaner(struct vsm_sc *sc, struct VSC_C_main *stats)
{
double now = VTIM_real();
struct vsm_range *vr, *vr2;
CHECK_OBJ_NOTNULL(sc, VSM_SC_MAGIC);
/* Move cooled off stuff to free list */
VTAILQ_FOREACH_SAFE(vr, &sc->r_cooling, list, vr2) {
if (vr->cool > now)
break;
VTAILQ_REMOVE(&sc->r_cooling, vr, list);
vsm_common_insert_free(sc, vr);
}
stats->vsm_free = sc->g_free;
stats->vsm_used = sc->g_used;
stats->vsm_cooling = sc->g_cooling;
stats->vsm_overflow = sc->g_overflow;
stats->vsm_overflowed = sc->c_overflow;
}
/*--------------------------------------------------------------------
* Allocate a chunk from VSM
*/
......@@ -160,7 +193,6 @@ VSM_common_alloc(struct vsm_sc *sc, ssize_t size,
const char *class, const char *type, const char *ident)
{
struct vsm_range *vr, *vr2, *vr3;
double now = VTIM_real();
unsigned l1, l2;
CHECK_OBJ_NOTNULL(sc, VSM_SC_MAGIC);
......@@ -174,14 +206,6 @@ VSM_common_alloc(struct vsm_sc *sc, ssize_t size,
AN(ident);
assert(strlen(ident) < sizeof(vr->chunk->ident));
/* Move cooled off stuff to free list */
VTAILQ_FOREACH_SAFE(vr, &sc->r_cooling, list, vr2) {
if (vr->cool > now)
break;
VTAILQ_REMOVE(&sc->r_cooling, vr, list);
vsm_common_insert_free(sc, vr);
}
l1 = RUP2(size + sizeof(struct VSM_chunk), 16);
l2 = RUP2(size + 2 * sizeof(struct VSM_chunk), 16);
......@@ -213,12 +237,15 @@ VSM_common_alloc(struct vsm_sc *sc, ssize_t size,
AN(vr);
vr->ptr = malloc(size);
AN(vr->ptr);
vr->len = size;
VTAILQ_INSERT_TAIL(&sc->r_bogus, vr, list);
/* XXX: log + stats */
sc->g_overflow += vr->len;
sc->c_overflow += vr->len;
return (vr->ptr);
}
/* XXX: stats ? */
sc->g_free -= vr->len;
sc->g_used += vr->len;
/* Zero the entire allocation, to avoid garbage confusing readers */
memset(sc->b + vr->off, 0, vr->len);
......@@ -263,7 +290,10 @@ VSM_common_free(struct vsm_sc *sc, void *ptr)
VTAILQ_FOREACH(vr, &sc->r_used, list) {
if (vr->ptr != ptr)
continue;
/* XXX: stats ? */
sc->g_used -= vr->len;
sc->g_cooling += vr->len;
vr2 = VTAILQ_NEXT(vr, list);
VTAILQ_REMOVE(&sc->r_used, vr, list);
VTAILQ_INSERT_TAIL(&sc->r_cooling, vr, list);
......@@ -278,15 +308,18 @@ VSM_common_free(struct vsm_sc *sc, void *ptr)
VWMB();
return;
}
/* Look in bogus list, free */
VTAILQ_FOREACH(vr, &sc->r_bogus, list) {
if (vr->ptr == ptr) {
VTAILQ_REMOVE(&sc->r_bogus, vr, list);
FREE_OBJ(vr);
/* XXX: stats ? */
free(ptr);
return;
}
if (vr->ptr != ptr)
continue;
sc->g_overflow -= vr->len;
VTAILQ_REMOVE(&sc->r_bogus, vr, list);
FREE_OBJ(vr);
free(ptr);
return;
}
/* Panic */
assert(ptr == NULL);
......@@ -326,7 +359,7 @@ VSM_common_delete(struct vsm_sc **scp)
}
/*--------------------------------------------------------------------
* Copy one VSM to another
* Copy all chunks in one VSM segment to another VSM segment
*/
void
......
......@@ -359,3 +359,38 @@ VSC_F(vmods, uint64_t, 0, 'i', "Loaded VMODs", "")
VSC_F(n_gzip, uint64_t, 0, 'a', "Gzip operations", "")
VSC_F(n_gunzip, uint64_t, 0, 'a', "Gunzip operations", "")
/**********************************************************************/
VSC_F(vsm_free, uint64_t, 0, 'g',
"Free VSM space",
"Number of bytes free in the shared memory used to communicate"
" with tools like varnishstat, varnishlog etc."
)
VSC_F(vsm_used, uint64_t, 0, 'g',
"Used VSM space",
"Number of bytes used in the shared memory used to communicate"
" with tools like varnishstat, varnishlog etc."
)
VSC_F(vsm_cooling, uint64_t, 0, 'g',
"Cooling VSM space",
"Number of bytes which will soon (max 1 minute) be freed"
" in the shared memory used to communicate"
" with tools like varnishstat, varnishlog etc."
)
VSC_F(vsm_overflow, uint64_t, 0, 'g',
"Overflow VSM space",
"Number of bytes which does not fit"
" in the shared memory used to communicate"
" with tools like varnishstat, varnishlog etc."
)
VSC_F(vsm_overflowed, uint64_t, 0, 'c',
"Overflowed VSM space",
"Total number of bytes which did not fit"
" in the shared memory used to communicate"
" with tools like varnishstat, varnishlog etc."
)
......@@ -37,7 +37,7 @@
* In particular we want the readers to seamlessly jump from one VSM instance
* to another when the child restarts.
*
* The VSM life-cycle there is:
* The VSM segment life-cycle is:
*
* Manager creates VSM file under temp name
*
......@@ -54,7 +54,7 @@
* it will zero the alloc_seq in it, before replacing the file.
*
* Subscribers will have to monitor two things to make sure they have
* the current VSM instance: The alloc_seq field and the inode number
* the current VSM instance: The alloc_seq field and the dev+inode
* of the path-name. The former check is by far the cheaper and the
* latter check should only be employed when lack of activity in the
* VSM segment raises suspicion that something has happened.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment