301 lines
5.7 KiB
C
301 lines
5.7 KiB
C
/* $NetBSD: pdsim.c,v 1.2 2006/10/14 04:43:41 yamt Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c)2006 YAMAMOTO Takashi,
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "pdsim.h"
|
|
|
|
#define SHOWFAULT
|
|
#if defined(SHOWQLEN) || defined(SHOWIRR)
|
|
#undef SHOWFAULT
|
|
#endif
|
|
|
|
#undef READAHEAD
|
|
|
|
struct vm_page *pages;
|
|
|
|
struct uvmexp uvmexp;
|
|
|
|
int npagein;
|
|
int nfault;
|
|
int raio;
|
|
int rahit;
|
|
|
|
int lastacc[MAXID];
|
|
int irr[MAXID];
|
|
int ts;
|
|
|
|
struct {
|
|
int fault;
|
|
int hit;
|
|
} stats[MAXID];
|
|
|
|
TAILQ_HEAD(, vm_page) freeq;
|
|
|
|
struct vm_page *
|
|
pdsim_pagealloc(struct uvm_object *obj, int idx)
|
|
{
|
|
struct vm_page *pg;
|
|
|
|
pg = TAILQ_FIRST(&freeq);
|
|
if (pg == NULL) {
|
|
return NULL;
|
|
}
|
|
TAILQ_REMOVE(&freeq, pg, pageq);
|
|
pg->offset = idx << PAGE_SHIFT;
|
|
pg->uanon = NULL;
|
|
pg->uobject = obj;
|
|
pg->pqflags = 0;
|
|
obj->pages[idx] = pg;
|
|
uvmexp.free--;
|
|
uvmexp.filepages++;
|
|
|
|
return pg;
|
|
}
|
|
|
|
void
|
|
pdsim_pagefree(struct vm_page *pg)
|
|
{
|
|
struct uvm_object *obj;
|
|
|
|
KASSERT(pg != NULL);
|
|
|
|
#if defined(SHOWFREE)
|
|
if (pg->offset != -1) {
|
|
int idx = pg->offset >> PAGE_SHIFT;
|
|
printf("%d %d # FREE IRR\n", idx, irr[idx]);
|
|
}
|
|
#endif /* defined(SHOWFREE) */
|
|
|
|
uvmpdpol_pagedequeue(pg);
|
|
|
|
KASSERT(pg->uanon == NULL);
|
|
obj = pg->uobject;
|
|
if (obj != NULL) {
|
|
int idx;
|
|
|
|
idx = pg->offset >> PAGE_SHIFT;
|
|
KASSERT(obj->pages[idx] == pg);
|
|
obj->pages[idx] = NULL;
|
|
uvmexp.filepages--;
|
|
}
|
|
TAILQ_INSERT_HEAD(&freeq, pg, pageq);
|
|
uvmexp.free++;
|
|
}
|
|
|
|
static struct vm_page *
|
|
pdsim_pagelookup(struct uvm_object *obj, int index)
|
|
{
|
|
struct vm_page *pg;
|
|
|
|
pg = obj->pages[index];
|
|
|
|
return pg;
|
|
}
|
|
|
|
static void
|
|
pdsim_pagemarkreferenced(struct vm_page *pg)
|
|
{
|
|
|
|
pg->_mdflags |= MDPG_REFERENCED;
|
|
}
|
|
|
|
boolean_t
|
|
pmap_is_referenced(struct vm_page *pg)
|
|
{
|
|
|
|
return pg->_mdflags & MDPG_REFERENCED;
|
|
}
|
|
|
|
boolean_t
|
|
pmap_clear_reference(struct vm_page *pg)
|
|
{
|
|
boolean_t referenced = pmap_is_referenced(pg);
|
|
|
|
pg->_mdflags &= ~MDPG_REFERENCED;
|
|
|
|
return referenced;
|
|
}
|
|
|
|
static void
|
|
pdsim_init(int n)
|
|
{
|
|
struct vm_page *pg;
|
|
int i;
|
|
|
|
uvmpdpol_init();
|
|
uvmexp.npages = n;
|
|
uvmpdpol_reinit();
|
|
|
|
TAILQ_INIT(&freeq);
|
|
pages = calloc(n, sizeof(*pg));
|
|
for (i = 0; i < n; i++) {
|
|
pg = &pages[i];
|
|
pg->offset = -1;
|
|
pdsim_pagefree(pg);
|
|
}
|
|
}
|
|
|
|
static void
|
|
pdsim_reclaimone(void)
|
|
{
|
|
struct vm_page *pg;
|
|
|
|
uvmexp.freetarg = 1;
|
|
while (uvmexp.free < uvmexp.freetarg) {
|
|
uvmpdpol_tune();
|
|
uvmpdpol_scaninit();
|
|
pg = uvmpdpol_selectvictim();
|
|
if (pg != NULL) {
|
|
pdsim_pagefree(pg);
|
|
}
|
|
uvmpdpol_balancequeue(0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fault(struct uvm_object *obj, int index)
|
|
{
|
|
struct vm_page *pg;
|
|
|
|
DPRINTF("fault: %d -> ", index);
|
|
nfault++;
|
|
ts++;
|
|
if (lastacc[index]) {
|
|
irr[index] = ts - lastacc[index];
|
|
}
|
|
lastacc[index] = ts;
|
|
stats[index].fault++;
|
|
pg = pdsim_pagelookup(obj, index);
|
|
if (pg) {
|
|
DPRINTF("cached\n");
|
|
pdsim_pagemarkreferenced(pg);
|
|
stats[index].hit++;
|
|
if ((pg->_mdflags & MDPG_SPECULATIVE) != 0) {
|
|
pg->_mdflags &= ~MDPG_SPECULATIVE;
|
|
rahit++;
|
|
}
|
|
return;
|
|
}
|
|
DPRINTF("miss\n");
|
|
retry:
|
|
pg = pdsim_pagealloc(obj, index);
|
|
if (pg == NULL) {
|
|
pdsim_reclaimone();
|
|
goto retry;
|
|
}
|
|
npagein++;
|
|
#if defined(SHOWFAULT)
|
|
printf("%d # FLT\n", index);
|
|
#endif
|
|
pdsim_pagemarkreferenced(pg);
|
|
uvmpdpol_pageactivate(pg);
|
|
uvmpdpol_pageactivate(pg);
|
|
dump("fault");
|
|
#if defined(READAHEAD)
|
|
pg = pdsim_pagelookup(obj, index + 1);
|
|
if (pg == NULL) {
|
|
ra_retry:
|
|
pg = pdsim_pagealloc(obj, index + 1);
|
|
if (pg == NULL) {
|
|
pdsim_reclaimone();
|
|
goto ra_retry;
|
|
}
|
|
raio++;
|
|
pg->_mdflags |= MDPG_SPECULATIVE;
|
|
#if defined(SHOWFAULT)
|
|
printf("%d # READ-AHEAD\n", index + 1);
|
|
#endif
|
|
}
|
|
uvmpdpol_pageenqueue(pg);
|
|
dump("read-ahead");
|
|
#endif /* defined(READAHEAD) */
|
|
}
|
|
|
|
struct uvm_object obj;
|
|
|
|
static void
|
|
test(void)
|
|
{
|
|
memset(&obj, 0, sizeof(obj));
|
|
char *ln;
|
|
|
|
for (;; free(ln)) {
|
|
int i;
|
|
int ch;
|
|
|
|
ln = fparseln(stdin, NULL, NULL, NULL, 0);
|
|
if (ln == NULL) {
|
|
break;
|
|
}
|
|
ch = *ln;
|
|
if (ch == '\0') {
|
|
break;
|
|
}
|
|
if (ch == 'd') {
|
|
dump("test");
|
|
continue;
|
|
}
|
|
i = atoi(ln);
|
|
fault(&obj, i);
|
|
#if defined(SHOWQLEN)
|
|
showqlen();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if defined(DEBUG)
|
|
static void
|
|
dumpstats(void)
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAXID; i++) {
|
|
if (stats[i].fault == 0) {
|
|
continue;
|
|
}
|
|
DPRINTF("[%d] %d/%d %d\n", i,
|
|
stats[i].hit, stats[i].fault, irr[i]);
|
|
}
|
|
}
|
|
#endif /* defined(DEBUG) */
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
|
|
setvbuf(stderr, NULL, _IOFBF, 0); /* XXX */
|
|
|
|
pdsim_init(atoi(argv[1]));
|
|
test();
|
|
DPRINTF("io %d (%d + ra %d) / flt %d\n",
|
|
npagein + raio, npagein, raio, nfault);
|
|
DPRINTF("rahit / raio= %d / %d\n", rahit, raio);
|
|
#if defined(DEBUG)
|
|
dumpstats();
|
|
#endif
|
|
exit(0);
|
|
}
|