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