xref: /netbsd-src/regress/sys/uvm/pdsim/pdsim.c (revision 705759a99aab29c9fb41114f560cfa79feadd33d)
1*705759a9Syamt /*	$NetBSD: pdsim.c,v 1.2 2006/10/14 04:43:41 yamt Exp $	*/
2dbdfc1f6Syamt 
3dbdfc1f6Syamt /*-
4dbdfc1f6Syamt  * Copyright (c)2006 YAMAMOTO Takashi,
5dbdfc1f6Syamt  * All rights reserved.
6dbdfc1f6Syamt  *
7dbdfc1f6Syamt  * Redistribution and use in source and binary forms, with or without
8dbdfc1f6Syamt  * modification, are permitted provided that the following conditions
9dbdfc1f6Syamt  * are met:
10dbdfc1f6Syamt  * 1. Redistributions of source code must retain the above copyright
11dbdfc1f6Syamt  *    notice, this list of conditions and the following disclaimer.
12dbdfc1f6Syamt  * 2. Redistributions in binary form must reproduce the above copyright
13dbdfc1f6Syamt  *    notice, this list of conditions and the following disclaimer in the
14dbdfc1f6Syamt  *    documentation and/or other materials provided with the distribution.
15dbdfc1f6Syamt  *
16dbdfc1f6Syamt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17dbdfc1f6Syamt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18dbdfc1f6Syamt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19dbdfc1f6Syamt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20dbdfc1f6Syamt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21dbdfc1f6Syamt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22dbdfc1f6Syamt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23dbdfc1f6Syamt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24dbdfc1f6Syamt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25dbdfc1f6Syamt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26dbdfc1f6Syamt  * SUCH DAMAGE.
27dbdfc1f6Syamt  */
28dbdfc1f6Syamt 
29dbdfc1f6Syamt #include "pdsim.h"
30dbdfc1f6Syamt 
31dbdfc1f6Syamt #define	SHOWFAULT
32dbdfc1f6Syamt #if defined(SHOWQLEN) || defined(SHOWIRR)
33dbdfc1f6Syamt #undef SHOWFAULT
34dbdfc1f6Syamt #endif
35dbdfc1f6Syamt 
36dbdfc1f6Syamt #undef	READAHEAD
37dbdfc1f6Syamt 
38dbdfc1f6Syamt struct vm_page *pages;
39dbdfc1f6Syamt 
40dbdfc1f6Syamt struct uvmexp uvmexp;
41dbdfc1f6Syamt 
42dbdfc1f6Syamt int npagein;
43dbdfc1f6Syamt int nfault;
44dbdfc1f6Syamt int raio;
45dbdfc1f6Syamt int rahit;
46dbdfc1f6Syamt 
47dbdfc1f6Syamt int lastacc[MAXID];
48dbdfc1f6Syamt int irr[MAXID];
49dbdfc1f6Syamt int ts;
50dbdfc1f6Syamt 
51dbdfc1f6Syamt struct {
52dbdfc1f6Syamt 	int fault;
53dbdfc1f6Syamt 	int hit;
54dbdfc1f6Syamt } stats[MAXID];
55dbdfc1f6Syamt 
56dbdfc1f6Syamt TAILQ_HEAD(, vm_page) freeq;
57dbdfc1f6Syamt 
58dbdfc1f6Syamt struct vm_page *
pdsim_pagealloc(struct uvm_object * obj,int idx)59dbdfc1f6Syamt pdsim_pagealloc(struct uvm_object *obj, int idx)
60dbdfc1f6Syamt {
61dbdfc1f6Syamt 	struct vm_page *pg;
62dbdfc1f6Syamt 
63dbdfc1f6Syamt 	pg = TAILQ_FIRST(&freeq);
64dbdfc1f6Syamt 	if (pg == NULL) {
65dbdfc1f6Syamt 		return NULL;
66dbdfc1f6Syamt 	}
67dbdfc1f6Syamt 	TAILQ_REMOVE(&freeq, pg, pageq);
68dbdfc1f6Syamt 	pg->offset = idx << PAGE_SHIFT;
69dbdfc1f6Syamt 	pg->uanon = NULL;
70dbdfc1f6Syamt 	pg->uobject = obj;
71dbdfc1f6Syamt 	pg->pqflags = 0;
72dbdfc1f6Syamt 	obj->pages[idx] = pg;
73dbdfc1f6Syamt 	uvmexp.free--;
74dbdfc1f6Syamt 	uvmexp.filepages++;
75dbdfc1f6Syamt 
76dbdfc1f6Syamt 	return pg;
77dbdfc1f6Syamt }
78dbdfc1f6Syamt 
79dbdfc1f6Syamt void
pdsim_pagefree(struct vm_page * pg)80dbdfc1f6Syamt pdsim_pagefree(struct vm_page *pg)
81dbdfc1f6Syamt {
82dbdfc1f6Syamt 	struct uvm_object *obj;
83dbdfc1f6Syamt 
84dbdfc1f6Syamt 	KASSERT(pg != NULL);
85dbdfc1f6Syamt 
86dbdfc1f6Syamt #if defined(SHOWFREE)
87dbdfc1f6Syamt 	if (pg->offset != -1) {
88dbdfc1f6Syamt 		int idx = pg->offset >> PAGE_SHIFT;
89dbdfc1f6Syamt 		printf("%d %d	# FREE IRR\n", idx, irr[idx]);
90dbdfc1f6Syamt 	}
91dbdfc1f6Syamt #endif /* defined(SHOWFREE) */
92dbdfc1f6Syamt 
93dbdfc1f6Syamt 	uvmpdpol_pagedequeue(pg);
94dbdfc1f6Syamt 
95dbdfc1f6Syamt 	KASSERT(pg->uanon == NULL);
96dbdfc1f6Syamt 	obj = pg->uobject;
97dbdfc1f6Syamt 	if (obj != NULL) {
98dbdfc1f6Syamt 		int idx;
99dbdfc1f6Syamt 
100dbdfc1f6Syamt 		idx = pg->offset >> PAGE_SHIFT;
101dbdfc1f6Syamt 		KASSERT(obj->pages[idx] == pg);
102dbdfc1f6Syamt 		obj->pages[idx] = NULL;
103dbdfc1f6Syamt 		uvmexp.filepages--;
104dbdfc1f6Syamt 	}
105dbdfc1f6Syamt 	TAILQ_INSERT_HEAD(&freeq, pg, pageq);
106dbdfc1f6Syamt 	uvmexp.free++;
107dbdfc1f6Syamt }
108dbdfc1f6Syamt 
109dbdfc1f6Syamt static struct vm_page *
pdsim_pagelookup(struct uvm_object * obj,int index)110dbdfc1f6Syamt pdsim_pagelookup(struct uvm_object *obj, int index)
111dbdfc1f6Syamt {
112dbdfc1f6Syamt 	struct vm_page *pg;
113dbdfc1f6Syamt 
114dbdfc1f6Syamt 	pg = obj->pages[index];
115dbdfc1f6Syamt 
116dbdfc1f6Syamt 	return pg;
117dbdfc1f6Syamt }
118dbdfc1f6Syamt 
119dbdfc1f6Syamt static void
pdsim_pagemarkreferenced(struct vm_page * pg)120dbdfc1f6Syamt pdsim_pagemarkreferenced(struct vm_page *pg)
121dbdfc1f6Syamt {
122dbdfc1f6Syamt 
123dbdfc1f6Syamt 	pg->_mdflags |= MDPG_REFERENCED;
124dbdfc1f6Syamt }
125dbdfc1f6Syamt 
126dbdfc1f6Syamt boolean_t
pmap_is_referenced(struct vm_page * pg)127dbdfc1f6Syamt pmap_is_referenced(struct vm_page *pg)
128dbdfc1f6Syamt {
129dbdfc1f6Syamt 
130dbdfc1f6Syamt 	return pg->_mdflags & MDPG_REFERENCED;
131dbdfc1f6Syamt }
132dbdfc1f6Syamt 
133dbdfc1f6Syamt boolean_t
pmap_clear_reference(struct vm_page * pg)134dbdfc1f6Syamt pmap_clear_reference(struct vm_page *pg)
135dbdfc1f6Syamt {
136dbdfc1f6Syamt 	boolean_t referenced = pmap_is_referenced(pg);
137dbdfc1f6Syamt 
138dbdfc1f6Syamt 	pg->_mdflags &= ~MDPG_REFERENCED;
139dbdfc1f6Syamt 
140dbdfc1f6Syamt 	return referenced;
141dbdfc1f6Syamt }
142dbdfc1f6Syamt 
143dbdfc1f6Syamt static void
pdsim_init(int n)144dbdfc1f6Syamt pdsim_init(int n)
145dbdfc1f6Syamt {
146dbdfc1f6Syamt 	struct vm_page *pg;
147dbdfc1f6Syamt 	int i;
148dbdfc1f6Syamt 
149dbdfc1f6Syamt 	uvmpdpol_init();
150dbdfc1f6Syamt 	uvmexp.npages = n;
151dbdfc1f6Syamt 	uvmpdpol_reinit();
152dbdfc1f6Syamt 
153dbdfc1f6Syamt 	TAILQ_INIT(&freeq);
154dbdfc1f6Syamt 	pages = calloc(n, sizeof(*pg));
155dbdfc1f6Syamt 	for (i = 0; i < n; i++) {
156dbdfc1f6Syamt 		pg = &pages[i];
157dbdfc1f6Syamt 		pg->offset = -1;
158dbdfc1f6Syamt 		pdsim_pagefree(pg);
159dbdfc1f6Syamt 	}
160dbdfc1f6Syamt }
161dbdfc1f6Syamt 
162dbdfc1f6Syamt static void
pdsim_reclaimone(void)163dbdfc1f6Syamt pdsim_reclaimone(void)
164dbdfc1f6Syamt {
165dbdfc1f6Syamt 	struct vm_page *pg;
166dbdfc1f6Syamt 
167dbdfc1f6Syamt 	uvmexp.freetarg = 1;
168dbdfc1f6Syamt 	while (uvmexp.free < uvmexp.freetarg) {
169dbdfc1f6Syamt 		uvmpdpol_tune();
170dbdfc1f6Syamt 		uvmpdpol_scaninit();
171dbdfc1f6Syamt 		pg = uvmpdpol_selectvictim();
172dbdfc1f6Syamt 		if (pg != NULL) {
173dbdfc1f6Syamt 			pdsim_pagefree(pg);
174dbdfc1f6Syamt 		}
175dbdfc1f6Syamt 		uvmpdpol_balancequeue(0);
176dbdfc1f6Syamt 	}
177dbdfc1f6Syamt }
178dbdfc1f6Syamt 
179dbdfc1f6Syamt static void
fault(struct uvm_object * obj,int index)180dbdfc1f6Syamt fault(struct uvm_object *obj, int index)
181dbdfc1f6Syamt {
182dbdfc1f6Syamt 	struct vm_page *pg;
183dbdfc1f6Syamt 
184dbdfc1f6Syamt 	DPRINTF("fault: %d -> ", index);
185dbdfc1f6Syamt 	nfault++;
186dbdfc1f6Syamt 	ts++;
187dbdfc1f6Syamt 	if (lastacc[index]) {
188dbdfc1f6Syamt 		irr[index] = ts - lastacc[index];
189dbdfc1f6Syamt 	}
190dbdfc1f6Syamt 	lastacc[index] = ts;
191dbdfc1f6Syamt 	stats[index].fault++;
192dbdfc1f6Syamt 	pg = pdsim_pagelookup(obj, index);
193dbdfc1f6Syamt 	if (pg) {
194dbdfc1f6Syamt 		DPRINTF("cached\n");
195dbdfc1f6Syamt 		pdsim_pagemarkreferenced(pg);
196dbdfc1f6Syamt 		stats[index].hit++;
197dbdfc1f6Syamt 		if ((pg->_mdflags & MDPG_SPECULATIVE) != 0) {
198dbdfc1f6Syamt 			pg->_mdflags &= ~MDPG_SPECULATIVE;
199dbdfc1f6Syamt 			rahit++;
200dbdfc1f6Syamt 		}
201dbdfc1f6Syamt 		return;
202dbdfc1f6Syamt 	}
203dbdfc1f6Syamt 	DPRINTF("miss\n");
204dbdfc1f6Syamt retry:
205dbdfc1f6Syamt 	pg = pdsim_pagealloc(obj, index);
206dbdfc1f6Syamt 	if (pg == NULL) {
207dbdfc1f6Syamt 		pdsim_reclaimone();
208dbdfc1f6Syamt 		goto retry;
209dbdfc1f6Syamt 	}
210dbdfc1f6Syamt 	npagein++;
211dbdfc1f6Syamt #if defined(SHOWFAULT)
212dbdfc1f6Syamt 	printf("%d	# FLT\n", index);
213dbdfc1f6Syamt #endif
214dbdfc1f6Syamt 	pdsim_pagemarkreferenced(pg);
215dbdfc1f6Syamt 	uvmpdpol_pageactivate(pg);
216dbdfc1f6Syamt 	uvmpdpol_pageactivate(pg);
217dbdfc1f6Syamt 	dump("fault");
218dbdfc1f6Syamt #if defined(READAHEAD)
219dbdfc1f6Syamt 	pg = pdsim_pagelookup(obj, index + 1);
220dbdfc1f6Syamt 	if (pg == NULL) {
221dbdfc1f6Syamt ra_retry:
222dbdfc1f6Syamt 		pg = pdsim_pagealloc(obj, index + 1);
223dbdfc1f6Syamt 		if (pg == NULL) {
224dbdfc1f6Syamt 			pdsim_reclaimone();
225dbdfc1f6Syamt 			goto ra_retry;
226dbdfc1f6Syamt 		}
227dbdfc1f6Syamt 		raio++;
228dbdfc1f6Syamt 		pg->_mdflags |= MDPG_SPECULATIVE;
229dbdfc1f6Syamt #if defined(SHOWFAULT)
230dbdfc1f6Syamt 		printf("%d	# READ-AHEAD\n", index + 1);
231dbdfc1f6Syamt #endif
232dbdfc1f6Syamt 	}
233dbdfc1f6Syamt 	uvmpdpol_pageenqueue(pg);
234dbdfc1f6Syamt 	dump("read-ahead");
235dbdfc1f6Syamt #endif /* defined(READAHEAD) */
236dbdfc1f6Syamt }
237dbdfc1f6Syamt 
238dbdfc1f6Syamt struct uvm_object obj;
239dbdfc1f6Syamt 
240dbdfc1f6Syamt static void
test(void)241dbdfc1f6Syamt test(void)
242dbdfc1f6Syamt {
243dbdfc1f6Syamt 	memset(&obj, 0, sizeof(obj));
244dbdfc1f6Syamt 	char *ln;
245dbdfc1f6Syamt 
246dbdfc1f6Syamt 	for (;; free(ln)) {
247dbdfc1f6Syamt 		int i;
248dbdfc1f6Syamt 		int ch;
249dbdfc1f6Syamt 
250dbdfc1f6Syamt 		ln = fparseln(stdin, NULL, NULL, NULL, 0);
251dbdfc1f6Syamt 		if (ln == NULL) {
252dbdfc1f6Syamt 			break;
253dbdfc1f6Syamt 		}
254dbdfc1f6Syamt 		ch = *ln;
255dbdfc1f6Syamt 		if (ch == '\0') {
256dbdfc1f6Syamt 			break;
257dbdfc1f6Syamt 		}
258dbdfc1f6Syamt 		if (ch == 'd') {
259dbdfc1f6Syamt 			dump("test");
260dbdfc1f6Syamt 			continue;
261dbdfc1f6Syamt 		}
262dbdfc1f6Syamt 		i = atoi(ln);
263dbdfc1f6Syamt 		fault(&obj, i);
264dbdfc1f6Syamt #if defined(SHOWQLEN)
265dbdfc1f6Syamt 		showqlen();
266dbdfc1f6Syamt #endif
267dbdfc1f6Syamt 	}
268dbdfc1f6Syamt }
269dbdfc1f6Syamt 
270*705759a9Syamt #if defined(DEBUG)
271dbdfc1f6Syamt static void
dumpstats(void)272dbdfc1f6Syamt dumpstats(void)
273dbdfc1f6Syamt {
274dbdfc1f6Syamt 	int i;
275dbdfc1f6Syamt 	for (i = 0; i < MAXID; i++) {
276dbdfc1f6Syamt 		if (stats[i].fault == 0) {
277dbdfc1f6Syamt 			continue;
278dbdfc1f6Syamt 		}
279dbdfc1f6Syamt 		DPRINTF("[%d] %d/%d %d\n", i,
280dbdfc1f6Syamt 		    stats[i].hit, stats[i].fault, irr[i]);
281dbdfc1f6Syamt 	}
282dbdfc1f6Syamt }
283*705759a9Syamt #endif /* defined(DEBUG) */
284dbdfc1f6Syamt 
285dbdfc1f6Syamt int
main(int argc,char * argv[])286dbdfc1f6Syamt main(int argc, char *argv[])
287dbdfc1f6Syamt {
288dbdfc1f6Syamt 
289dbdfc1f6Syamt 	setvbuf(stderr, NULL, _IOFBF, 0); /* XXX */
290dbdfc1f6Syamt 
291dbdfc1f6Syamt 	pdsim_init(atoi(argv[1]));
292dbdfc1f6Syamt 	test();
293dbdfc1f6Syamt 	DPRINTF("io %d (%d + ra %d) / flt %d\n",
294dbdfc1f6Syamt 	    npagein + raio, npagein, raio, nfault);
295dbdfc1f6Syamt 	DPRINTF("rahit / raio= %d / %d\n", rahit, raio);
296dbdfc1f6Syamt #if defined(DEBUG)
297dbdfc1f6Syamt 	dumpstats();
298dbdfc1f6Syamt #endif
299dbdfc1f6Syamt 	exit(0);
300dbdfc1f6Syamt }
301