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