xref: /plan9/sys/src/cmd/venti/srv/icache.c (revision 06f339c0b55d53c35173aacde75f3fb952f2024f)
1368c31abSDavid du Colombier #include "stdinc.h"
2368c31abSDavid du Colombier #include "dat.h"
3368c31abSDavid du Colombier #include "fns.h"
4368c31abSDavid du Colombier 
5f9e1cf08SDavid du Colombier int icacheprefetch = 1;
6f9e1cf08SDavid du Colombier 
7368c31abSDavid du Colombier typedef struct ICache ICache;
8f9e1cf08SDavid du Colombier typedef struct IHash IHash;
9f9e1cf08SDavid du Colombier typedef struct ISum ISum;
10f9e1cf08SDavid du Colombier 
11368c31abSDavid du Colombier struct ICache
12368c31abSDavid du Colombier {
13f9e1cf08SDavid du Colombier 	QLock	lock;
14368c31abSDavid du Colombier 	Rendez	full;
15f9e1cf08SDavid du Colombier 	IHash	*hash;
16f9e1cf08SDavid du Colombier 	IEntry	*entries;
17f9e1cf08SDavid du Colombier 	int		nentries;
18f9e1cf08SDavid du Colombier 	IEntry	free;
19f9e1cf08SDavid du Colombier 	IEntry	clean;
20f9e1cf08SDavid du Colombier 	IEntry	dirty;
21368c31abSDavid du Colombier 	u32int	maxdirty;
22f9e1cf08SDavid du Colombier 	u32int	ndirty;
23f9e1cf08SDavid du Colombier 	AState	as;
24368c31abSDavid du Colombier 
25f9e1cf08SDavid du Colombier 	ISum	**sum;
26f9e1cf08SDavid du Colombier 	int		nsum;
27f9e1cf08SDavid du Colombier 	IHash	*shash;
28f9e1cf08SDavid du Colombier 	IEntry	*sentries;
29f9e1cf08SDavid du Colombier 	int		nsentries;
30368c31abSDavid du Colombier };
31368c31abSDavid du Colombier 
32368c31abSDavid du Colombier static ICache icache;
33368c31abSDavid du Colombier 
34368c31abSDavid du Colombier /*
35f9e1cf08SDavid du Colombier  * Hash table of IEntries
36368c31abSDavid du Colombier  */
37f9e1cf08SDavid du Colombier 
38f9e1cf08SDavid du Colombier struct IHash
39368c31abSDavid du Colombier {
40f9e1cf08SDavid du Colombier 	int bits;
41f9e1cf08SDavid du Colombier 	u32int size;
42f9e1cf08SDavid du Colombier 	IEntry **table;
43f9e1cf08SDavid du Colombier };
44f9e1cf08SDavid du Colombier 
45f9e1cf08SDavid du Colombier static IHash*
mkihash(int size1)46f9e1cf08SDavid du Colombier mkihash(int size1)
47f9e1cf08SDavid du Colombier {
48f9e1cf08SDavid du Colombier 	u32int size;
49f9e1cf08SDavid du Colombier 	int bits;
50f9e1cf08SDavid du Colombier 	IHash *ih;
51f9e1cf08SDavid du Colombier 
52f9e1cf08SDavid du Colombier 	bits = 0;
53f9e1cf08SDavid du Colombier 	size = 1;
54f9e1cf08SDavid du Colombier 	while(size < size1){
55f9e1cf08SDavid du Colombier 		bits++;
56f9e1cf08SDavid du Colombier 		size <<= 1;
57368c31abSDavid du Colombier 	}
58368c31abSDavid du Colombier 
59f9e1cf08SDavid du Colombier 	ih = vtmallocz(sizeof(IHash)+size*sizeof(ih->table[0]));
60f9e1cf08SDavid du Colombier 	ih->table = (IEntry**)(ih+1);
61f9e1cf08SDavid du Colombier 	ih->bits = bits;
62f9e1cf08SDavid du Colombier 	ih->size = size;
63f9e1cf08SDavid du Colombier 	return ih;
64f9e1cf08SDavid du Colombier }
65f9e1cf08SDavid du Colombier 
66f9e1cf08SDavid du Colombier static IEntry*
ihashlookup(IHash * ih,u8int score[VtScoreSize],int type)67f9e1cf08SDavid du Colombier ihashlookup(IHash *ih, u8int score[VtScoreSize], int type)
68368c31abSDavid du Colombier {
69f9e1cf08SDavid du Colombier 	u32int h;
70f9e1cf08SDavid du Colombier 	IEntry *ie;
71f9e1cf08SDavid du Colombier 
72f9e1cf08SDavid du Colombier 	h = hashbits(score, ih->bits);
73f9e1cf08SDavid du Colombier 	for(ie=ih->table[h]; ie; ie=ie->nexthash)
74f9e1cf08SDavid du Colombier 		if((type == -1 || type == ie->ia.type) && scorecmp(score, ie->score) == 0)
75f9e1cf08SDavid du Colombier 			return ie;
76f9e1cf08SDavid du Colombier 	return nil;
77f9e1cf08SDavid du Colombier }
78f9e1cf08SDavid du Colombier 
79f9e1cf08SDavid du Colombier static void
ihashdelete(IHash * ih,IEntry * ie,char * what)80f9e1cf08SDavid du Colombier ihashdelete(IHash *ih, IEntry *ie, char *what)
81f9e1cf08SDavid du Colombier {
82f9e1cf08SDavid du Colombier 	u32int h;
83f9e1cf08SDavid du Colombier 	IEntry **l;
84f9e1cf08SDavid du Colombier 
85f9e1cf08SDavid du Colombier 	h = hashbits(ie->score, ih->bits);
86f9e1cf08SDavid du Colombier 	for(l=&ih->table[h]; *l; l=&(*l)->nexthash)
87f9e1cf08SDavid du Colombier 		if(*l == ie){
88f9e1cf08SDavid du Colombier 			*l = ie->nexthash;
89f9e1cf08SDavid du Colombier 			return;
90f9e1cf08SDavid du Colombier 		}
91f9e1cf08SDavid du Colombier 	fprint(2, "warning: %s %V not found in ihashdelete\n", what, ie->score);
92f9e1cf08SDavid du Colombier }
93f9e1cf08SDavid du Colombier 
94f9e1cf08SDavid du Colombier static void
ihashinsert(IHash * ih,IEntry * ie)95f9e1cf08SDavid du Colombier ihashinsert(IHash *ih, IEntry *ie)
96f9e1cf08SDavid du Colombier {
97f9e1cf08SDavid du Colombier 	u32int h;
98f9e1cf08SDavid du Colombier 
99f9e1cf08SDavid du Colombier 	h = hashbits(ie->score, ih->bits);
100f9e1cf08SDavid du Colombier 	ie->nexthash = ih->table[h];
101f9e1cf08SDavid du Colombier 	ih->table[h] = ie;
102f9e1cf08SDavid du Colombier }
103f9e1cf08SDavid du Colombier 
104f9e1cf08SDavid du Colombier 
105f9e1cf08SDavid du Colombier /*
106f9e1cf08SDavid du Colombier  * IEntry lists.
107f9e1cf08SDavid du Colombier  */
108f9e1cf08SDavid du Colombier 
109f9e1cf08SDavid du Colombier static IEntry*
popout(IEntry * ie)110f9e1cf08SDavid du Colombier popout(IEntry *ie)
111f9e1cf08SDavid du Colombier {
112f9e1cf08SDavid du Colombier 	if(ie->prev == nil && ie->next == nil)
113f9e1cf08SDavid du Colombier 		return ie;
114f9e1cf08SDavid du Colombier 	ie->prev->next = ie->next;
115f9e1cf08SDavid du Colombier 	ie->next->prev = ie->prev;
116f9e1cf08SDavid du Colombier 	ie->next = nil;
117f9e1cf08SDavid du Colombier 	ie->prev = nil;
118f9e1cf08SDavid du Colombier 	return ie;
119f9e1cf08SDavid du Colombier }
120f9e1cf08SDavid du Colombier 
121f9e1cf08SDavid du Colombier static IEntry*
poplast(IEntry * list)122f9e1cf08SDavid du Colombier poplast(IEntry *list)
123f9e1cf08SDavid du Colombier {
124f9e1cf08SDavid du Colombier 	if(list->prev == list)
125f9e1cf08SDavid du Colombier 		return nil;
126f9e1cf08SDavid du Colombier 	return popout(list->prev);
127f9e1cf08SDavid du Colombier }
128f9e1cf08SDavid du Colombier 
129f9e1cf08SDavid du Colombier static IEntry*
pushfirst(IEntry * list,IEntry * ie)130f9e1cf08SDavid du Colombier pushfirst(IEntry *list, IEntry *ie)
131f9e1cf08SDavid du Colombier {
132f9e1cf08SDavid du Colombier 	popout(ie);
133f9e1cf08SDavid du Colombier 	ie->prev = list;
134f9e1cf08SDavid du Colombier 	ie->next = list->next;
135f9e1cf08SDavid du Colombier 	ie->prev->next = ie;
136f9e1cf08SDavid du Colombier 	ie->next->prev = ie;
137f9e1cf08SDavid du Colombier 	return ie;
138f9e1cf08SDavid du Colombier }
139f9e1cf08SDavid du Colombier 
140f9e1cf08SDavid du Colombier /*
141f9e1cf08SDavid du Colombier  * Arena summary cache.
142f9e1cf08SDavid du Colombier  */
143f9e1cf08SDavid du Colombier struct ISum
144f9e1cf08SDavid du Colombier {
145f9e1cf08SDavid du Colombier 	QLock	lock;
146f9e1cf08SDavid du Colombier 	IEntry	*entries;
147f9e1cf08SDavid du Colombier 	int	nentries;
148f9e1cf08SDavid du Colombier 	int	loaded;
149f9e1cf08SDavid du Colombier 	u64int addr;
150f9e1cf08SDavid du Colombier 	u64int limit;
151f9e1cf08SDavid du Colombier 	Arena *arena;
152f9e1cf08SDavid du Colombier 	int g;
153f9e1cf08SDavid du Colombier };
154f9e1cf08SDavid du Colombier 
155f9e1cf08SDavid du Colombier static ISum*
scachelookup(u64int addr)156f9e1cf08SDavid du Colombier scachelookup(u64int addr)
157f9e1cf08SDavid du Colombier {
158f9e1cf08SDavid du Colombier 	int i;
159f9e1cf08SDavid du Colombier 	ISum *s;
160f9e1cf08SDavid du Colombier 
161f9e1cf08SDavid du Colombier 	for(i=0; i<icache.nsum; i++){
162f9e1cf08SDavid du Colombier 		s = icache.sum[i];
163f9e1cf08SDavid du Colombier 		if(s->addr <= addr && addr < s->limit){
164f9e1cf08SDavid du Colombier 			if(i > 0){
165f9e1cf08SDavid du Colombier 				memmove(icache.sum+1, icache.sum, i*sizeof icache.sum[0]);
166f9e1cf08SDavid du Colombier 				icache.sum[0] = s;
167f9e1cf08SDavid du Colombier 			}
168f9e1cf08SDavid du Colombier 			return s;
169f9e1cf08SDavid du Colombier 		}
170f9e1cf08SDavid du Colombier 	}
171f9e1cf08SDavid du Colombier 	return nil;
172f9e1cf08SDavid du Colombier }
173f9e1cf08SDavid du Colombier 
174f9e1cf08SDavid du Colombier static void
sumclear(ISum * s)175f9e1cf08SDavid du Colombier sumclear(ISum *s)
176f9e1cf08SDavid du Colombier {
177f9e1cf08SDavid du Colombier 	int i;
178f9e1cf08SDavid du Colombier 
179f9e1cf08SDavid du Colombier 	for(i=0; i<s->nentries; i++)
180f9e1cf08SDavid du Colombier 		ihashdelete(icache.shash, &s->entries[i], "scache");
181f9e1cf08SDavid du Colombier 	s->nentries = 0;
182f9e1cf08SDavid du Colombier 	s->loaded = 0;
183f9e1cf08SDavid du Colombier 	s->addr = 0;
184f9e1cf08SDavid du Colombier 	s->limit = 0;
185f9e1cf08SDavid du Colombier 	s->arena = nil;
186f9e1cf08SDavid du Colombier 	s->g = 0;
187f9e1cf08SDavid du Colombier }
188f9e1cf08SDavid du Colombier 
189f9e1cf08SDavid du Colombier static ISum*
scacheevict(void)190f9e1cf08SDavid du Colombier scacheevict(void)
191f9e1cf08SDavid du Colombier {
192f9e1cf08SDavid du Colombier 	ISum *s;
193f9e1cf08SDavid du Colombier 	int i;
194f9e1cf08SDavid du Colombier 
195f9e1cf08SDavid du Colombier 	for(i=icache.nsum-1; i>=0; i--){
196f9e1cf08SDavid du Colombier 		s = icache.sum[i];
197f9e1cf08SDavid du Colombier 		if(canqlock(&s->lock)){
198f9e1cf08SDavid du Colombier 			if(i > 0){
199f9e1cf08SDavid du Colombier 				memmove(icache.sum+1, icache.sum, i*sizeof icache.sum[0]);
200f9e1cf08SDavid du Colombier 				icache.sum[0] = s;
201f9e1cf08SDavid du Colombier 			}
202f9e1cf08SDavid du Colombier 			sumclear(s);
203f9e1cf08SDavid du Colombier 			return s;
204f9e1cf08SDavid du Colombier 		}
205f9e1cf08SDavid du Colombier 	}
206f9e1cf08SDavid du Colombier 	return nil;
207f9e1cf08SDavid du Colombier }
208f9e1cf08SDavid du Colombier 
209f9e1cf08SDavid du Colombier static void
scachehit(u64int addr)210f9e1cf08SDavid du Colombier scachehit(u64int addr)
211f9e1cf08SDavid du Colombier {
212f9e1cf08SDavid du Colombier 	scachelookup(addr);	/* for move-to-front */
213f9e1cf08SDavid du Colombier }
214f9e1cf08SDavid du Colombier 
215f9e1cf08SDavid du Colombier static void
scachesetup(ISum * s,u64int addr)216f9e1cf08SDavid du Colombier scachesetup(ISum *s, u64int addr)
217f9e1cf08SDavid du Colombier {
218f9e1cf08SDavid du Colombier 	u64int addr0, limit;
219f9e1cf08SDavid du Colombier 	int g;
220f9e1cf08SDavid du Colombier 
221f9e1cf08SDavid du Colombier 	s->arena = amapitoag(mainindex, addr, &addr0, &limit, &g);
222f9e1cf08SDavid du Colombier 	s->addr = addr0;
223f9e1cf08SDavid du Colombier 	s->limit = limit;
224f9e1cf08SDavid du Colombier 	s->g = g;
225f9e1cf08SDavid du Colombier }
226f9e1cf08SDavid du Colombier 
227f9e1cf08SDavid du Colombier static void
scacheload(ISum * s)228f9e1cf08SDavid du Colombier scacheload(ISum *s)
229f9e1cf08SDavid du Colombier {
230f9e1cf08SDavid du Colombier 	int i, n;
231f9e1cf08SDavid du Colombier 
232f9e1cf08SDavid du Colombier 	s->loaded = 1;
233f9e1cf08SDavid du Colombier 	n = asumload(s->arena, s->g, s->entries, ArenaCIGSize);
234f9e1cf08SDavid du Colombier 	/*
235f9e1cf08SDavid du Colombier 	 * n can be less then ArenaCIGSize, either if the clump group
236f9e1cf08SDavid du Colombier 	 * is the last in the arena and is only partially filled, or if there
237f9e1cf08SDavid du Colombier 	 * are corrupt clumps in the group -- those are not returned.
238f9e1cf08SDavid du Colombier 	 */
239f9e1cf08SDavid du Colombier 	for(i=0; i<n; i++){
240f9e1cf08SDavid du Colombier 		s->entries[i].ia.addr += s->addr;
241f9e1cf08SDavid du Colombier 		ihashinsert(icache.shash, &s->entries[i]);
242f9e1cf08SDavid du Colombier 	}
243f9e1cf08SDavid du Colombier //fprint(2, "%T scacheload %s %d - %d entries\n", s->arena->name, s->g, n);
244f9e1cf08SDavid du Colombier 	addstat(StatScachePrefetch, n);
245f9e1cf08SDavid du Colombier 	s->nentries = n;
246f9e1cf08SDavid du Colombier }
247f9e1cf08SDavid du Colombier 
248f9e1cf08SDavid du Colombier static ISum*
scachemiss(u64int addr)249f9e1cf08SDavid du Colombier scachemiss(u64int addr)
250f9e1cf08SDavid du Colombier {
251f9e1cf08SDavid du Colombier 	ISum *s;
252f9e1cf08SDavid du Colombier 
25323566e0cSDavid du Colombier 	if(!icacheprefetch)
25423566e0cSDavid du Colombier 		return nil;
255f9e1cf08SDavid du Colombier 	s = scachelookup(addr);
256f9e1cf08SDavid du Colombier 	if(s == nil){
257f9e1cf08SDavid du Colombier 		/* first time: make an entry in the cache but don't populate it yet */
258f9e1cf08SDavid du Colombier 		s = scacheevict();
259f9e1cf08SDavid du Colombier 		if(s == nil)
260f9e1cf08SDavid du Colombier 			return nil;
261f9e1cf08SDavid du Colombier 		scachesetup(s, addr);
262f9e1cf08SDavid du Colombier 		qunlock(&s->lock);
263f9e1cf08SDavid du Colombier 		return nil;
264f9e1cf08SDavid du Colombier 	}
265f9e1cf08SDavid du Colombier 
266f9e1cf08SDavid du Colombier 	/* second time: load from disk */
267f9e1cf08SDavid du Colombier 	qlock(&s->lock);
268f9e1cf08SDavid du Colombier 	if(s->loaded || !icacheprefetch){
269f9e1cf08SDavid du Colombier 		qunlock(&s->lock);
270f9e1cf08SDavid du Colombier 		return nil;
271f9e1cf08SDavid du Colombier 	}
272f9e1cf08SDavid du Colombier 
273f9e1cf08SDavid du Colombier 	return s;	/* locked */
274f9e1cf08SDavid du Colombier }
275f9e1cf08SDavid du Colombier 
276f9e1cf08SDavid du Colombier /*
277f9e1cf08SDavid du Colombier  * Index cache.
278f9e1cf08SDavid du Colombier  */
279f9e1cf08SDavid du Colombier 
280f9e1cf08SDavid du Colombier void
initicache(u32int mem0)281f9e1cf08SDavid du Colombier initicache(u32int mem0)
282f9e1cf08SDavid du Colombier {
283f9e1cf08SDavid du Colombier 	u32int mem;
284f9e1cf08SDavid du Colombier 	int i, entries, scache;
285f9e1cf08SDavid du Colombier 
286f9e1cf08SDavid du Colombier 	icache.full.l = &icache.lock;
287f9e1cf08SDavid du Colombier 
288f9e1cf08SDavid du Colombier 	mem = mem0;
289f9e1cf08SDavid du Colombier 	entries = mem / (sizeof(IEntry)+sizeof(IEntry*));
290f9e1cf08SDavid du Colombier 	scache = (entries/8) / ArenaCIGSize;
291f9e1cf08SDavid du Colombier 	entries -= entries/8;
292f9e1cf08SDavid du Colombier 	if(scache < 4)
293f9e1cf08SDavid du Colombier 		scache = 4;
294f9e1cf08SDavid du Colombier 	if(scache > 16)
295f9e1cf08SDavid du Colombier 		scache = 16;
296f9e1cf08SDavid du Colombier 	if(entries < 1000)
297f9e1cf08SDavid du Colombier 		entries = 1000;
298f9e1cf08SDavid du Colombier fprint(2, "icache %,d bytes = %,d entries; %d scache\n", mem0, entries, scache);
299f9e1cf08SDavid du Colombier 
300f9e1cf08SDavid du Colombier 	icache.clean.prev = icache.clean.next = &icache.clean;
301f9e1cf08SDavid du Colombier 	icache.dirty.prev = icache.dirty.next = &icache.dirty;
302f9e1cf08SDavid du Colombier 	icache.free.prev = icache.free.next = &icache.free;
303f9e1cf08SDavid du Colombier 
304f9e1cf08SDavid du Colombier 	icache.hash = mkihash(entries);
305f9e1cf08SDavid du Colombier 	icache.nentries = entries;
306f9e1cf08SDavid du Colombier 	setstat(StatIcacheSize, entries);
307f9e1cf08SDavid du Colombier 	icache.entries = vtmallocz(entries*sizeof icache.entries[0]);
308f9e1cf08SDavid du Colombier 	icache.maxdirty = entries / 2;
309f9e1cf08SDavid du Colombier 	for(i=0; i<entries; i++)
310f9e1cf08SDavid du Colombier 		pushfirst(&icache.free, &icache.entries[i]);
311f9e1cf08SDavid du Colombier 
312f9e1cf08SDavid du Colombier 	icache.nsum = scache;
313f9e1cf08SDavid du Colombier 	icache.sum = vtmallocz(scache*sizeof icache.sum[0]);
314f9e1cf08SDavid du Colombier 	icache.sum[0] = vtmallocz(scache*sizeof icache.sum[0][0]);
315f9e1cf08SDavid du Colombier 	icache.nsentries = scache * ArenaCIGSize;
316f9e1cf08SDavid du Colombier 	icache.sentries = vtmallocz(scache*ArenaCIGSize*sizeof icache.sentries[0]);
317f9e1cf08SDavid du Colombier 	icache.shash = mkihash(scache*ArenaCIGSize);
318f9e1cf08SDavid du Colombier 	for(i=0; i<scache; i++){
319f9e1cf08SDavid du Colombier 		icache.sum[i] = icache.sum[0] + i;
320f9e1cf08SDavid du Colombier 		icache.sum[i]->entries = icache.sentries + i*ArenaCIGSize;
321f9e1cf08SDavid du Colombier 	}
322f9e1cf08SDavid du Colombier }
323f9e1cf08SDavid du Colombier 
324f9e1cf08SDavid du Colombier 
325f9e1cf08SDavid du Colombier static IEntry*
evictlru(void)326f9e1cf08SDavid du Colombier evictlru(void)
327f9e1cf08SDavid du Colombier {
328f9e1cf08SDavid du Colombier 	IEntry *ie;
329f9e1cf08SDavid du Colombier 
330f9e1cf08SDavid du Colombier 	ie = poplast(&icache.clean);
331f9e1cf08SDavid du Colombier 	if(ie == nil)
332f9e1cf08SDavid du Colombier 		return nil;
333f9e1cf08SDavid du Colombier 	ihashdelete(icache.hash, ie, "evictlru");
334f9e1cf08SDavid du Colombier 	return ie;
335f9e1cf08SDavid du Colombier }
336f9e1cf08SDavid du Colombier 
337f9e1cf08SDavid du Colombier static void
icacheinsert(u8int score[VtScoreSize],IAddr * ia,int state)338f9e1cf08SDavid du Colombier icacheinsert(u8int score[VtScoreSize], IAddr *ia, int state)
339f9e1cf08SDavid du Colombier {
340f9e1cf08SDavid du Colombier 	IEntry *ie;
341f9e1cf08SDavid du Colombier 
342f9e1cf08SDavid du Colombier 	if((ie = poplast(&icache.free)) == nil && (ie = evictlru()) == nil){
343f9e1cf08SDavid du Colombier 		addstat(StatIcacheStall, 1);
344f9e1cf08SDavid du Colombier 		while((ie = poplast(&icache.free)) == nil && (ie = evictlru()) == nil){
345f9e1cf08SDavid du Colombier 			// Could safely return here if state == IEClean.
346f9e1cf08SDavid du Colombier 			// But if state == IEDirty, have to wait to make
347f9e1cf08SDavid du Colombier 			// sure we don't lose an index write.
348f9e1cf08SDavid du Colombier 			// Let's wait all the time.
349f9e1cf08SDavid du Colombier 			flushdcache();
350f9e1cf08SDavid du Colombier 			kickicache();
351f9e1cf08SDavid du Colombier 			rsleep(&icache.full);
352f9e1cf08SDavid du Colombier 		}
353f9e1cf08SDavid du Colombier 		addstat(StatIcacheStall, -1);
354f9e1cf08SDavid du Colombier 	}
355f9e1cf08SDavid du Colombier 
356f9e1cf08SDavid du Colombier 	memmove(ie->score, score, VtScoreSize);
357f9e1cf08SDavid du Colombier 	ie->state = state;
358f9e1cf08SDavid du Colombier 	ie->ia = *ia;
359f9e1cf08SDavid du Colombier 	if(state == IEClean){
360f9e1cf08SDavid du Colombier 		addstat(StatIcachePrefetch, 1);
361f9e1cf08SDavid du Colombier 		pushfirst(&icache.clean, ie);
362f9e1cf08SDavid du Colombier 	}else{
363f9e1cf08SDavid du Colombier 		addstat(StatIcacheWrite, 1);
364f9e1cf08SDavid du Colombier 		assert(state == IEDirty);
365f9e1cf08SDavid du Colombier 		icache.ndirty++;
366f9e1cf08SDavid du Colombier 		setstat(StatIcacheDirty, icache.ndirty);
367f9e1cf08SDavid du Colombier 		delaykickicache();
368f9e1cf08SDavid du Colombier 		pushfirst(&icache.dirty, ie);
369f9e1cf08SDavid du Colombier 	}
370f9e1cf08SDavid du Colombier 	ihashinsert(icache.hash, ie);
371f9e1cf08SDavid du Colombier }
372f9e1cf08SDavid du Colombier 
373f9e1cf08SDavid du Colombier int
icachelookup(u8int score[VtScoreSize],int type,IAddr * ia)374f9e1cf08SDavid du Colombier icachelookup(u8int score[VtScoreSize], int type, IAddr *ia)
375f9e1cf08SDavid du Colombier {
376f9e1cf08SDavid du Colombier 	IEntry *ie;
377f9e1cf08SDavid du Colombier 
378f9e1cf08SDavid du Colombier 	qlock(&icache.lock);
379f9e1cf08SDavid du Colombier 	addstat(StatIcacheLookup, 1);
380f9e1cf08SDavid du Colombier 	if((ie = ihashlookup(icache.hash, score, type)) != nil){
381f9e1cf08SDavid du Colombier 		*ia = ie->ia;
382f9e1cf08SDavid du Colombier 		if(ie->state == IEClean)
383f9e1cf08SDavid du Colombier 			pushfirst(&icache.clean, ie);
384f9e1cf08SDavid du Colombier 		addstat(StatIcacheHit, 1);
385f9e1cf08SDavid du Colombier 		qunlock(&icache.lock);
386f9e1cf08SDavid du Colombier 		return 0;
387f9e1cf08SDavid du Colombier 	}
388f9e1cf08SDavid du Colombier 
389f9e1cf08SDavid du Colombier 	if((ie = ihashlookup(icache.shash, score, type)) != nil){
390f9e1cf08SDavid du Colombier 		*ia = ie->ia;
391f9e1cf08SDavid du Colombier 		icacheinsert(score, &ie->ia, IEClean);
392f9e1cf08SDavid du Colombier 		scachehit(ie->ia.addr);
393f9e1cf08SDavid du Colombier 		addstat(StatScacheHit, 1);
394f9e1cf08SDavid du Colombier 		qunlock(&icache.lock);
395f9e1cf08SDavid du Colombier 		return 0;
396f9e1cf08SDavid du Colombier 	}
397f9e1cf08SDavid du Colombier 	addstat(StatIcacheMiss, 1);
398f9e1cf08SDavid du Colombier 	qunlock(&icache.lock);
399f9e1cf08SDavid du Colombier 
400f9e1cf08SDavid du Colombier 	return -1;
401f9e1cf08SDavid du Colombier }
402f9e1cf08SDavid du Colombier 
403f9e1cf08SDavid du Colombier int
insertscore(u8int score[VtScoreSize],IAddr * ia,int state,AState * as)404f9e1cf08SDavid du Colombier insertscore(u8int score[VtScoreSize], IAddr *ia, int state, AState *as)
405f9e1cf08SDavid du Colombier {
406f9e1cf08SDavid du Colombier 	ISum *toload;
407f9e1cf08SDavid du Colombier 
408f9e1cf08SDavid du Colombier 	qlock(&icache.lock);
409f9e1cf08SDavid du Colombier 	icacheinsert(score, ia, state);
410f9e1cf08SDavid du Colombier 	if(state == IEClean)
411f9e1cf08SDavid du Colombier 		toload = scachemiss(ia->addr);
412f9e1cf08SDavid du Colombier 	else{
413f9e1cf08SDavid du Colombier 		assert(state == IEDirty);
414f9e1cf08SDavid du Colombier 		toload = nil;
415f9e1cf08SDavid du Colombier 		if(as == nil)
4161f9fb570SDavid du Colombier 			fprint(2, "%T insertscore IEDirty without as; called from %#p\n",
4171f9fb570SDavid du Colombier 				getcallerpc(&score));
418f9e1cf08SDavid du Colombier 		else{
419f9e1cf08SDavid du Colombier 			if(icache.as.aa > as->aa)
420f9e1cf08SDavid du Colombier 				fprint(2, "%T insertscore: aa moving backward: %#llux -> %#llux\n", icache.as.aa, as->aa);
421f9e1cf08SDavid du Colombier 			icache.as = *as;
422f9e1cf08SDavid du Colombier 		}
423f9e1cf08SDavid du Colombier 	}
424f9e1cf08SDavid du Colombier 	qunlock(&icache.lock);
425f9e1cf08SDavid du Colombier 	if(toload){
426f9e1cf08SDavid du Colombier 		scacheload(toload);
427f9e1cf08SDavid du Colombier 		qunlock(&toload->lock);
428f9e1cf08SDavid du Colombier 	}
429f9e1cf08SDavid du Colombier 
430f9e1cf08SDavid du Colombier 	if(icache.ndirty >= icache.maxdirty)
431f9e1cf08SDavid du Colombier 		kickicache();
432f9e1cf08SDavid du Colombier 
433f9e1cf08SDavid du Colombier 	/*
434f9e1cf08SDavid du Colombier 	 * It's okay not to do this under icache.lock.
435f9e1cf08SDavid du Colombier 	 * Calling insertscore only happens when we hold
436f9e1cf08SDavid du Colombier 	 * the lump, meaning any searches for this block
437f9e1cf08SDavid du Colombier 	 * will hit in the lump cache until after we return.
438f9e1cf08SDavid du Colombier 	 */
439f9e1cf08SDavid du Colombier 	if(state == IEDirty)
440f9e1cf08SDavid du Colombier 		markbloomfilter(mainindex->bloom, score);
441f9e1cf08SDavid du Colombier 
442f9e1cf08SDavid du Colombier 	return 0;
443f9e1cf08SDavid du Colombier }
444f9e1cf08SDavid du Colombier 
445f9e1cf08SDavid du Colombier int
lookupscore(u8int score[VtScoreSize],int type,IAddr * ia)446f9e1cf08SDavid du Colombier lookupscore(u8int score[VtScoreSize], int type, IAddr *ia)
447f9e1cf08SDavid du Colombier {
448f9e1cf08SDavid du Colombier 	int ms, ret;
44923566e0cSDavid du Colombier 	IEntry d;
45023566e0cSDavid du Colombier 
45123566e0cSDavid du Colombier 	if(icachelookup(score, type, ia) >= 0){
45223566e0cSDavid du Colombier 		addstat(StatIcacheRead, 1);
45323566e0cSDavid du Colombier 		return 0;
45423566e0cSDavid du Colombier 	}
455f9e1cf08SDavid du Colombier 
456f9e1cf08SDavid du Colombier 	ms = msec();
45723566e0cSDavid du Colombier 	addstat(StatIcacheFill, 1);
45823566e0cSDavid du Colombier 	if(loadientry(mainindex, score, type, &d) < 0)
45923566e0cSDavid du Colombier 		ret = -1;
46023566e0cSDavid du Colombier 	else{
46123566e0cSDavid du Colombier 		ret = 0;
46223566e0cSDavid du Colombier 		insertscore(score, &d.ia, IEClean, nil);
46323566e0cSDavid du Colombier 		*ia = d.ia;
46423566e0cSDavid du Colombier 	}
46523566e0cSDavid du Colombier 	addstat2(StatIcacheRead, 1, StatIcacheReadTime, msec() - ms);
466f9e1cf08SDavid du Colombier 	return ret;
467368c31abSDavid du Colombier }
468368c31abSDavid du Colombier 
469368c31abSDavid du Colombier u32int
hashbits(u8int * sc,int bits)470368c31abSDavid du Colombier hashbits(u8int *sc, int bits)
471368c31abSDavid du Colombier {
472368c31abSDavid du Colombier 	u32int v;
473368c31abSDavid du Colombier 
474368c31abSDavid du Colombier 	v = (sc[0] << 24) | (sc[1] << 16) | (sc[2] << 8) | sc[3];
475368c31abSDavid du Colombier 	if(bits < 32)
476368c31abSDavid du Colombier 		 v >>= (32 - bits);
477368c31abSDavid du Colombier 	return v;
478368c31abSDavid du Colombier }
479368c31abSDavid du Colombier 
480f9e1cf08SDavid du Colombier ulong
icachedirtyfrac(void)481f9e1cf08SDavid du Colombier icachedirtyfrac(void)
482368c31abSDavid du Colombier {
483f9e1cf08SDavid du Colombier 	return (vlong)icache.ndirty*IcacheFrac / icache.nentries;
484368c31abSDavid du Colombier }
485368c31abSDavid du Colombier 
486368c31abSDavid du Colombier /*
487f9e1cf08SDavid du Colombier  * Return a singly-linked list of dirty index entries.
488f9e1cf08SDavid du Colombier  * with 32-bit hash numbers between lo and hi
489f9e1cf08SDavid du Colombier  * and address < limit.
490368c31abSDavid du Colombier  */
491368c31abSDavid du Colombier IEntry*
icachedirty(u32int lo,u32int hi,u64int limit)492368c31abSDavid du Colombier icachedirty(u32int lo, u32int hi, u64int limit)
493368c31abSDavid du Colombier {
494368c31abSDavid du Colombier 	u32int h;
495368c31abSDavid du Colombier 	IEntry *ie, *dirty;
496368c31abSDavid du Colombier 
497368c31abSDavid du Colombier 	dirty = nil;
498368c31abSDavid du Colombier 	trace(TraceProc, "icachedirty enter");
499368c31abSDavid du Colombier 	qlock(&icache.lock);
500f9e1cf08SDavid du Colombier 	for(ie = icache.dirty.next; ie != &icache.dirty; ie=ie->next){
501*06f339c0SDavid du Colombier 		if(ie->state == IEDirty && ie->ia.addr <= limit){
502368c31abSDavid du Colombier 			h = hashbits(ie->score, 32);
503368c31abSDavid du Colombier 			if(lo <= h && h <= hi){
504368c31abSDavid du Colombier 				ie->nextdirty = dirty;
505368c31abSDavid du Colombier 				dirty = ie;
506368c31abSDavid du Colombier 			}
507368c31abSDavid du Colombier 		}
508f9e1cf08SDavid du Colombier 	}
509368c31abSDavid du Colombier 	qunlock(&icache.lock);
510368c31abSDavid du Colombier 	trace(TraceProc, "icachedirty exit");
511368c31abSDavid du Colombier 	if(dirty == nil)
512368c31abSDavid du Colombier 		flushdcache();
513368c31abSDavid du Colombier 	return dirty;
514368c31abSDavid du Colombier }
515368c31abSDavid du Colombier 
516f9e1cf08SDavid du Colombier AState
icachestate(void)517f9e1cf08SDavid du Colombier icachestate(void)
518f9e1cf08SDavid du Colombier {
519f9e1cf08SDavid du Colombier 	AState as;
520f9e1cf08SDavid du Colombier 
521f9e1cf08SDavid du Colombier 	qlock(&icache.lock);
522f9e1cf08SDavid du Colombier 	as = icache.as;
523f9e1cf08SDavid du Colombier 	qunlock(&icache.lock);
524f9e1cf08SDavid du Colombier 	return as;
525f9e1cf08SDavid du Colombier }
526f9e1cf08SDavid du Colombier 
527f9e1cf08SDavid du Colombier /*
528f9e1cf08SDavid du Colombier  * The singly-linked non-circular list of index entries ie
529f9e1cf08SDavid du Colombier  * has been written to disk.  Move them to the clean list.
530f9e1cf08SDavid du Colombier  */
531368c31abSDavid du Colombier void
icacheclean(IEntry * ie)532368c31abSDavid du Colombier icacheclean(IEntry *ie)
533368c31abSDavid du Colombier {
534f9e1cf08SDavid du Colombier 	IEntry *next;
535f9e1cf08SDavid du Colombier 
536f9e1cf08SDavid du Colombier 	trace(TraceProc, "icacheclean enter");
537368c31abSDavid du Colombier 	qlock(&icache.lock);
538f9e1cf08SDavid du Colombier 	for(; ie; ie=next){
539f9e1cf08SDavid du Colombier 		assert(ie->state == IEDirty);
540f9e1cf08SDavid du Colombier 		next = ie->nextdirty;
541f9e1cf08SDavid du Colombier 		ie->nextdirty = nil;
542f9e1cf08SDavid du Colombier 		popout(ie); /* from icache.dirty */
543368c31abSDavid du Colombier 		icache.ndirty--;
544f9e1cf08SDavid du Colombier 		ie->state = IEClean;
545f9e1cf08SDavid du Colombier 		pushfirst(&icache.clean, ie);
546368c31abSDavid du Colombier 	}
547368c31abSDavid du Colombier 	setstat(StatIcacheDirty, icache.ndirty);
548368c31abSDavid du Colombier 	rwakeupall(&icache.full);
549368c31abSDavid du Colombier 	qunlock(&icache.lock);
550f9e1cf08SDavid du Colombier 	trace(TraceProc, "icacheclean exit");
551368c31abSDavid du Colombier }
552368c31abSDavid du Colombier 
553368c31abSDavid du Colombier void
emptyicache(void)554368c31abSDavid du Colombier emptyicache(void)
555368c31abSDavid du Colombier {
556368c31abSDavid du Colombier 	int i;
557f9e1cf08SDavid du Colombier 	IEntry *ie;
558f9e1cf08SDavid du Colombier 	ISum *s;
559368c31abSDavid du Colombier 
560368c31abSDavid du Colombier 	qlock(&icache.lock);
561f9e1cf08SDavid du Colombier 	while((ie = evictlru()) != nil)
562f9e1cf08SDavid du Colombier 		pushfirst(&icache.free, ie);
563f9e1cf08SDavid du Colombier 	for(i=0; i<icache.nsum; i++){
564f9e1cf08SDavid du Colombier 		s = icache.sum[i];
565f9e1cf08SDavid du Colombier 		qlock(&s->lock);
566f9e1cf08SDavid du Colombier 		sumclear(s);
567f9e1cf08SDavid du Colombier 		qunlock(&s->lock);
568368c31abSDavid du Colombier 	}
569368c31abSDavid du Colombier 	qunlock(&icache.lock);
570368c31abSDavid du Colombier }
571f9e1cf08SDavid du Colombier 
572