forked from SDL-Hercules-390/hyperion
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cache.h
370 lines (296 loc) · 16.7 KB
/
cache.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/* CACHE.H (c)Copyright Greg Smith, 2002-2012 */
/* Buffer Cache Manager */
/* */
/* Released under "The Q Public License Version 1" */
/* (http://www.hercules-390.org/herclic.html) as modifications to */
/* Hercules. */
/*-------------------------------------------------------------------
Description:
Manages multiple caches in a multi-threaded environment. A cache
is dynamically created and destroyed. It's size or number of
entries is also dynamically determined. A cache entry contains
an identifying `key', `flags' which indicate whether an entry is
busy or not, and a `buf' which is a pointer to the cached object.
Cache entry:
The structure of a cache entry is:
U64 key;
U32 flag;
int len;
void *buf;
int value;
U64 age;
The first 8 bits of the flag indicates if the entry is `busy' or
not. If any of the first 8 bits are non-zero then the entry is
considered `busy' and will not be stolen or otherwise reused.
APIs:
General query functions:
int cache_nbr(int ix); [0]
Number of entries
int cache_busy(int ix);
Number of busy entries
int cache_empty(int ix);
Number of empty entries [1]
int cache_waiters(int ix);
Number of waiters for a non-busy cache entry
S64 cache_size(int ix);
Size of all allocated objects
S64 cache_hits(int ix);
Number of successful lookups
S64 cache_misses(int ix);
Number of unsuccessful lookups
int cache_busy_percent(int ix);
Percentage (0 .. 100) of entries that are busy
int cache_empty_percent(int ix);
Percentage of entries that are empty [1]
int cache_hit_percent(int ix);
Percentage of successful lookups to total lookups
Notes [0] `ix' identifies the cache. This is an integer
and is reserved in `cache.h'
[1] An empty entry contains a zero key value.
A valid key should not be all zeroes
(0x0000000000000000) or all ones
(0xffffffffffffffff). All ones is used to
indicate an error circumstance.
Entry specific functions:
U64 cache_getkey(int ix, int i); [0]
Return key for the specified cache entry
U64 cache_setkey(int ix, int i, U64 key);
Set the key for the specified cache entry;
the old key is returned
U32 cache_getflag(int ix, int i);
Return the flag for the specified cache entry
U32 cache_setflag(int ix, int i, U32 andbits, U32 orbits);
Set the flag for the specified cache entry; first
the `andbits' value is `and'ed against the entry then
the `orbits' value is `or'ed against the entry. The
old flag is returned.
U64 cache_getage(int ix, int i); [1]
Return age for the specified cache entry
U64 cache_setage(int ix, int i);
Set age for the specified cache entry
void *cache_getbuf(int ix, int i, int len);
Return address of the object buf for the cache entry.
If `len' is non-zero, then if the current object
is null or `len' is greater than the current object
length then the old object is freed and a new
object is obtained.
void *cache_setbuf(int ix, int i, void *buf, int len);
The old object address and length is replaced.
The address of the old object is returned and
can be freed using `free()'.
int cache_getlen(int ix, int i);
Return the length of the current object
Notes [0] `i' is the index of the entry in cache `ix'
[1] `age' is a sequentially incremented value and
does not correspond to date or time
Locking functions:
int cache_lock(int ix);
Obtain the lock for cache `ix'. If the cache does
not exist then it will be created. Generally, the
lock should be obtained when referencing cache
entries and must be held when a cache entry status
may change from `busy' to `not busy' or vice versa.
Likewise, the lock must be held when a cache entry
changes from `empty' to `not empty' or vice versa.
int cache_unlock(int ix);
Release the cache lock
Search functions:
int cache_lookup(int ix, U64 key, int *o);
Search cache `ix' for entry matching `key'.
If a non-NULL pointer `o' is provided, then the
oldest or preferred cache entry index is returned
that is available to be stolen.
int cache_scan (int ix, int (rtn)(), void *data);
Scan a cache routine entry by entry calling routine
`rtn'. Parameters passed to the routine are
`(int *answer, int ix, int i, void *data)' where
`ix' is the cache index, `i' is the cache entry
index and `data' is the value passed to cache_scan.
`*answer' is initialized to -1 and can be set by
the scan subroutine. This will be the value returned
by cache_scan. If the routine returns a non-zero
value then the scan is terminated.
Other functions:
int cache_wait(int ix);
Wait for a non-busy cache entry to become available.
Typically called after `cache_lookup' was
unsuccessful and `*o' is -1.
int cache_release(int ix, int i, int flag);
Release the cache entry. If flag is CACHE_FREEBUF
then the object buffer is also freed.
-------------------------------------------------------------------*/
#ifndef _HERCULES_CACHE_H
#define _HERCULES_CACHE_H 1
#include "hercules.h"
/*-------------------------------------------------------------------*/
/* Reserve cache indexes here */
/*-------------------------------------------------------------------*/
#define CACHE_MAX_INDEX 8 /* Max number caches [0..7] */
#define CACHE_DEVBUF 0 /* Device Buffer cache */
#define CACHE_L2 1 /* L2 cache */
#define CACHE_2 2 /* (available) */
#define CACHE_3 3 /* (available) */
#define CACHE_4 4 /* (available) */
#define CACHE_5 5 /* (available) */
#define CACHE_6 6 /* (available) */
#define CACHE_7 7 /* (available) */
/*-------------------------------------------------------------------*/
/* Cache entry */
/*-------------------------------------------------------------------*/
typedef struct _CACHE { /* Cache entry */
U64 key; /* Key */
U32 flag; /* Flags */
int len; /* Buffer length */
void *buf; /* Buffer address */
int value; /* Arbitrary value */
U64 age; /* Age */
} CACHE;
/*-------------------------------------------------------------------*/
/* Cache header */
/*-------------------------------------------------------------------*/
typedef struct _CACHEBLK { /* Cache header */
int magic; /* Magic number */
int nbr; /* Number entries */
int busy; /* Number busy entries */
int empty; /* Number empty entries */
int waiters; /* Number waiters */
int waits; /* Number times waited */
S64 size; /* Allocated buffer size */
S64 hits; /* Number lookup hits */
S64 fasthits; /* Number fast lookup hits */
S64 misses; /* Number lookup misses */
U64 age; /* Age counter */
LOCK lock; /* Lock */
COND waitcond; /* Wait for available entry */
CACHE *cache; /* Cache table address */
time_t atime; /* Time last adjustment */
time_t wtime; /* Time last wait */
int adjusts; /* Number of adjustments */
} CACHEBLK;
/*-------------------------------------------------------------------*/
/* Flag definitions */
/*-------------------------------------------------------------------*/
#define CACHE_BUSY 0xFF000000 /* Busy bits */
#define CACHE_TYPE 0x000000FF /* Type bits */
#define CACHE_FREEBUF 1 /* Free buf on release */
#define CACHE_MAGIC 0x01CACE10 /* Magic number */
#define CACHE_DEFAULT_NBR 229 /* Initial entries (prime) */
//FIXME the line below increases the size for CACHE_L2. Since each
// cckd device always has an active l2 entry this number
// actually limits the number of cckd devices that can be
// attached.
// This is a workaround to increase the max number of devices
#define CACHE_DEFAULT_L2_NBR 1031 /* Initial entries for L2 */
#define CACHE_WAITTIME 1000 /* Wait time for entry(usec) */
#define CACHE_ADJUST_INTERVAL 15 /* Adjustment interval (sec) */
#define CACHE_ADJUST_NUMBER 128 /* Uninhibited nbr entries */
#define CACHE_ADJUST_BUSY1 70 /* Increase when this busy 1 */
#define CACHE_ADJUST_BUSY2 80 /* Increase when this busy 2 */
#define CACHE_ADJUST_RESIZE 8 /* Nbr entries adjusted */
#define CACHE_ADJUST_EMPTY 16 /* Decrease this many empty */
#define CACHE_ADJUST_HIT1 60 /* Increase hit% this low 1 */
#define CACHE_ADJUST_HIT2 50 /* Increase hit% this low 2 */
#define CACHE_ADJUST_BUSY3 20 /* Decrease not this busy */
#define CACHE_ADJUST_HIT3 90 /* and hit% this high */
#define CACHE_ADJUST_SIZE (8*1024*1024)/* and size this high */
#define CACHE_ADJUST_WAITTIME 10 /* Increase last wait (sec) */
/*-------------------------------------------------------------------*/
/* Functions */
/*-------------------------------------------------------------------*/
CCH_DLL_IMPORT int cachestats_cmd(int argc, char *argv[], char *cmdline);
int cache_nbr(int ix);
int cache_busy(int ix);
int cache_empty(int ix);
int cache_waiters(int ix);
S64 cache_size(int ix);
S64 cache_hits(int ix);
S64 cache_misses(int ix);
int cache_busy_percent(int ix);
int cache_empty_percent(int ix);
int cache_hit_percent(int ix);
int cache_lookup(int ix, U64 key, int *o);
typedef int CACHE_SCAN_RTN (int *answer, int ix, int i, void *data);
int cache_scan (int ix, CACHE_SCAN_RTN rtn, void *data);
int cache_lock(int ix);
int cache_unlock(int ix);
int cache_wait(int ix);
U64 cache_getkey(int ix, int i);
U64 cache_setkey(int ix, int i, U64 key);
U32 cache_getflag(int ix, int i);
U32 cache_setflag(int ix, int i, U32 andbits, U32 orbits);
U64 cache_getage(int ix, int i);
U64 cache_setage(int ix, int i);
void *cache_getbuf(int ix, int i, int len);
void *cache_setbuf(int ix, int i, void *buf, int len);
int cache_getlen(int ix, int i);
int cache_getval(int ix, int i);
int cache_setval(int ix, int i, int val);
int cache_release(int ix, int i, int flag);
/*-------------------------------------------------------------------*/
/* Specific cache definitions (until a better place is found) */
/*-------------------------------------------------------------------*/
/*-------------------------------------------------------------------*/
/* Device buffer definitions */
/*-------------------------------------------------------------------*/
#define CCKD_CACHE_ACTIVE 0x80000000 /* Active entry */
#define CCKD_CACHE_READING 0x40000000 /* Entry being read */
#define CCKD_CACHE_WRITING 0x20000000 /* Entry being written */
#define CCKD_CACHE_IOBUSY (CCKD_CACHE_READING|CCKD_CACHE_WRITING)
#define CCKD_CACHE_IOWAIT 0x10000000 /* Waiters for i/o */
#define CCKD_CACHE_UPDATED 0x08000000 /* Buffer has been updated */
#define CCKD_CACHE_WRITE 0x04000000 /* Entry pending write */
#define CCKD_CACHE_USED 0x00800000 /* Entry has been used */
#define CKD_CACHE_ACTIVE 0x80000000 /* Active entry */
#define FBA_CACHE_ACTIVE 0x80000000 /* Active entry */
#define SHRD_CACHE_ACTIVE 0x80000000 /* Active entry */
#define DEVBUF_TYPE_SHARED 0x00000080 /* Shared entry type */
#define DEVBUF_TYPE_COMP 0x00000040 /* CCKD/CFBA entry type */
#define DEVBUF_TYPE_CKD 0x00000002 /* CKD entry type */
#define DEVBUF_TYPE_FBA 0x00000001 /* FBA entry type */
#define DEVBUF_TYPE_CCKD (DEVBUF_TYPE_COMP|DEVBUF_TYPE_CKD)
#define DEVBUF_TYPE_CFBA (DEVBUF_TYPE_COMP|DEVBUF_TYPE_FBA)
#define DEVBUF_TYPE_SCKD (DEVBUF_TYPE_SHARED|DEVBUF_TYPE_CKD)
#define DEVBUF_TYPE_SFBA (DEVBUF_TYPE_SHARED|DEVBUF_TYPE_FBA)
/*-------------------------------------------------------------------*/
#define CCKD_CACHE_GETKEY(_ix, _devnum, _trk) \
do { \
(_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF ); \
(_trk) = (U32)((cache_getkey(CACHE_DEVBUF,(_ix)) ) & 0xFFFFFFFF); \
} while (0)
#define CKD_CACHE_GETKEY(_ix, _devnum, _trk) \
{ \
(_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF ); \
(_trk) = (U32)((cache_getkey(CACHE_DEVBUF,(_ix)) )& 0xFFFFFFFF); \
}
#define FBA_CACHE_GETKEY(_ix, _devnum, _blkgrp) \
{ \
(_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF ); \
(_blkgrp) = (U32)((cache_getkey(CACHE_DEVBUF,(_ix)) ) & 0xFFFFFFFF); \
}
#define SHRD_CACHE_GETKEY(_ix, _devnum, _trk) \
{ \
(_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF ); \
(_trk) = (U32)((cache_getkey(CACHE_DEVBUF,(_ix)) ) & 0xFFFFFFFF); \
}
/*-------------------------------------------------------------------*/
#define CCKD_CACHE_SETKEY(_devnum, _trk) \
((U64)(((U64)(_devnum) << 32) | (U64)(_trk)))
#define CKD_CACHE_SETKEY(_devnum, _trk) \
((U64)(((U64)(_devnum) << 32) | (U64)(_trk)))
#define FBA_CACHE_SETKEY(_devnum, _blkgrp) \
((U64)(((U64)(_devnum) << 32) | (U64)(_blkgrp)))
#define SHRD_CACHE_SETKEY(_devnum, _trk) \
((U64)(((U64)(_devnum) << 32) | (U64)(_trk)))
/*-------------------------------------------------------------------*/
/* L2 definitions */
/*-------------------------------------------------------------------*/
#define L2_CACHE_ACTIVE 0x80000000 /* Active entry */
#define L2_CACHE_GETKEY(_ix, _sfx, _devnum, _trk) \
do { \
(_sfx) = (U16)((cache_getkey(CACHE_L2,(_ix)) >> 48) & 0xFFFF ); \
(_devnum) = (U16)((cache_getkey(CACHE_L2,(_ix)) >> 32) & 0xFFFF ); \
(_trk) = (U32)((cache_getkey(CACHE_L2,(_ix)) ) & 0xFFFFFFFF); \
} while (0)
#define L2_CACHE_SETKEY(_sfx, _devnum, _trk) \
((U64)(((U64)(_sfx) << 48) | ((U64)(_devnum) << 32) | (U64)(_trk)))
#endif /* _HERCULES_CACHE_H */