Skip to content

Commit 6af7b84

Browse files
committed
cachestat: bring back HITRATIO column
1 parent 5f5e118 commit 6af7b84

File tree

3 files changed

+125
-100
lines changed

3 files changed

+125
-100
lines changed

Diff for: man/man8/cachestat.8

+5-6
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,14 @@ Since this uses BPF, only the root user can use this tool.
1818
CONFIG_BPF and bcc.
1919
.SH EXAMPLES
2020
.TP
21-
Print summaries every five second:
21+
Print summaries every second:
2222
#
2323
.B cachestat
2424
.TP
25-
Print summaries every five seconds with timestamp:
25+
Print summaries every second with timestamp:
2626
#
2727
.B cachestat -T
2828
.TP
29-
Print summaries each second:
30-
#
31-
.B cachestat 1
32-
.TP
3329
Print output every five seconds, three times:
3430
#
3531
.B cachestat 5 3
@@ -51,6 +47,9 @@ Number of page cache misses.
5147
DIRTIES
5248
Number of dirty pages added to the page cache.
5349
.TP
50+
HITRATIO
51+
The hit ratio as a percentage.
52+
.TP
5453
READ_HIT%
5554
Read hit percent of page cache usage.
5655
.TP

Diff for: tools/cachestat.py

+32-41
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# 09-Sep-2015 Brendan Gregg Created this.
1616
# 06-Nov-2015 Allan McAleavy
1717
# 13-Jan-2016 Allan McAleavy run pep8 against program
18+
# 02-Feb-2019 Brendan Gregg Column shuffle, bring back %ratio
1819

1920
from __future__ import print_function
2021
from bcc import BPF
@@ -55,7 +56,7 @@ def get_meminfo():
5556
formatter_class=argparse.RawDescriptionHelpFormatter)
5657
parser.add_argument("-T", "--timestamp", action="store_true",
5758
help="include timestamp on output")
58-
parser.add_argument("interval", nargs="?", default=5,
59+
parser.add_argument("interval", nargs="?", default=1,
5960
help="output interval, in seconds")
6061
parser.add_argument("count", nargs="?", default=-1,
6162
help="number of outputs")
@@ -102,7 +103,7 @@ def get_meminfo():
102103
if tstamp:
103104
print("%-8s " % "TIME", end="")
104105
print("%8s %8s %8s %8s %12s %10s" %
105-
("TOTAL", "MISSES", "HITS", "DIRTIES", "BUFFERS_MB", "CACHED_MB"))
106+
("HITS", "MISSES", "DIRTIES", "HITRATIO", "BUFFERS_MB", "CACHED_MB"))
106107

107108
loop = 0
108109
exiting = 0
@@ -121,38 +122,36 @@ def get_meminfo():
121122

122123
counts = b["counts"]
123124
for k, v in sorted(counts.items(), key=lambda counts: counts[1].value):
124-
125-
if re.match(b'mark_page_accessed', b.ksym(k.ip)) is not None:
125+
func = b.ksym(k.ip)
126+
# partial string matches in case of .isra (necessary?)
127+
if func.find("mark_page_accessed") == 0:
126128
mpa = max(0, v.value)
127-
128-
if re.match(b'mark_buffer_dirty', b.ksym(k.ip)) is not None:
129+
if func.find("mark_buffer_dirty") == 0:
129130
mbd = max(0, v.value)
130-
131-
if re.match(b'add_to_page_cache_lru', b.ksym(k.ip)) is not None:
131+
if func.find("add_to_page_cache_lru") == 0:
132132
apcl = max(0, v.value)
133-
134-
if re.match(b'account_page_dirtied', b.ksym(k.ip)) is not None:
133+
if func.find("account_page_dirtied") == 0:
135134
apd = max(0, v.value)
136135

137-
# total = total cache accesses without counting dirties
138-
# misses = total of add to lru because of read misses
139-
total = (mpa - mbd)
140-
misses = (apcl - apd)
141-
142-
if total < 0:
143-
total = 0
144-
145-
if misses < 0:
146-
misses = 0
147-
148-
hits = total - misses
149-
150-
# If hits are < 0, then its possible misses are overestimated
151-
# due to possibly page cache read ahead adding more pages than
152-
# needed. In this case just assume misses as total and reset hits.
153-
if hits < 0:
154-
misses = total
155-
hits = 0
136+
# total = total cache accesses without counting dirties
137+
# misses = total of add to lru because of read misses
138+
total = mpa - mbd
139+
misses = apcl - apd
140+
if misses < 0:
141+
misses = 0
142+
if total < 0:
143+
total = 0
144+
hits = total - misses
145+
146+
# If hits are < 0, then its possible misses are overestimated
147+
# due to possibly page cache read ahead adding more pages than
148+
# needed. In this case just assume misses as total and reset hits.
149+
if hits < 0:
150+
misses = total
151+
hits = 0
152+
ratio = 0
153+
if total > 0:
154+
ratio = float(hits) / total
156155

157156
if debug:
158157
print("%d %d %d %d %d %d %d\n" %
@@ -167,18 +166,10 @@ def get_meminfo():
167166

168167
if tstamp:
169168
print("%-8s " % strftime("%H:%M:%S"), end="")
170-
print("%8d %8d %8d %8d %12.0f %10.0f" %
171-
(total, misses, hits, mbd, buff, cached))
172-
173-
mpa = 0
174-
mbd = 0
175-
apcl = 0
176-
apd = 0
177-
total = 0
178-
misses = 0
179-
hits = 0
180-
cached = 0
181-
buff = 0
169+
print("%8d %8d %8d %7.2f%% %12.0f %10.0f" %
170+
(hits, misses, mbd, 100 * ratio, buff, cached))
171+
172+
mpa = mbd = apcl = apd = total = misses = hits = cached = buff = 0
182173

183174
if exiting:
184175
print("Detaching...")

Diff for: tools/cachestat_example.txt

+88-53
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,91 @@
1-
# ./cachestat -h
2-
USAGE: ./cachestat [-T] [ interval [count] ]
1+
Demonstrations of cachestat, the Linux eBPF/bcc version.
32

4-
show Linux page cache hit/miss statistics including read and write hit %
3+
4+
cachestat shows hits and misses to the file system page cache. For example:
5+
6+
# cachestat
7+
HITS MISSES DIRTIES HITRATIO BUFFERS_MB CACHED_MB
8+
1132 0 4 100.00% 277 4367
9+
161 0 36 100.00% 277 4372
10+
16 0 28 100.00% 277 4372
11+
17154 13750 15 55.51% 277 4422
12+
19 0 1 100.00% 277 4422
13+
83 0 83 100.00% 277 4421
14+
16 0 1 100.00% 277 4423
15+
^C 0 -19 360 0.00% 277 4423
16+
Detaching...
17+
18+
While tracing, there was a burst of misses in the fourth second, bringing
19+
the hit ration down to 55%.
20+
21+
22+
This shows a 1 Gbyte uncached file that is read twice:
23+
24+
(root) ~ # ./cachestat.py
25+
HITS MISSES DIRTIES HITRATIO BUFFERS_MB CACHED_MB
26+
1 0 0 100.00% 5 191
27+
198 12136 0 1.61% 5 238
28+
1 11007 3 0.01% 5 281
29+
0 6384 0 0.00% 5 306
30+
1 14464 0 0.01% 5 363
31+
0 11776 0 0.00% 5 409
32+
1 11712 0 0.01% 5 454
33+
32 13184 0 0.24% 5 506
34+
0 11232 0 0.00% 5 550
35+
1 13056 0 0.01% 5 601
36+
16 14720 0 0.11% 5 658
37+
33 9920 0 0.33% 5 697
38+
0 13248 0 0.00% 5 749
39+
4 14144 0 0.03% 5 804
40+
0 9728 0 0.00% 5 842
41+
1 10816 0 0.01% 5 885
42+
808 13504 1 5.65% 5 938
43+
0 11409 0 0.00% 5 982
44+
0 11520 0 0.00% 5 1027
45+
0 15616 0 0.00% 5 1088
46+
1 9792 0 0.01% 5 1126
47+
0 8256 0 0.00% 5 1158
48+
1 9600 0 0.01% 5 1196
49+
599 4804 0 11.09% 5 1215
50+
1 0 0 100.00% 5 1215
51+
0 0 0 0.00% 5 1215
52+
3 1 0 75.00% 5 1215
53+
79536 34 0 99.96% 5 1215
54+
87693 274 4 99.69% 6 1214
55+
89018 3546 0 96.17% 7 1227
56+
33531 201 4 99.40% 7 1228
57+
22 44 0 33.33% 8 1228
58+
0 0 0 0.00% 8 1228
59+
73 21 2 77.66% 8 1228
60+
61+
It took 24 seconds to read the 1 Gbyte file the first time, shown in the output
62+
by the high MISSES rate and low HITRATIO. The second time it took 4 seconds,
63+
and the HITRATIO was around 99%.
64+
65+
66+
This output shows a 1 Gbyte file being created and added to the page cache:
67+
68+
(root) ~ # ./cachestat.py
69+
HITS MISSES DIRTIES HITRATIO BUFFERS_MB CACHED_MB
70+
1 0 0 100.00% 8 209
71+
0 0 165584 0.00% 8 856
72+
0 0 96505 0.00% 8 1233
73+
0 0 0 0.00% 8 1233
74+
75+
Note the high rate of DIRTIES, and the CACHED_MD size increases by 1024 Mbytes.
76+
77+
78+
USAGE message:
79+
80+
# cachestat -h
81+
usage: cachestat.py [-h] [-T] [interval] [count]
82+
83+
Count cache kernel function calls
84+
85+
positional arguments:
86+
interval output interval, in seconds
87+
count number of outputs
588

689
optional arguments:
7-
-T include timestamp on output
8-
9-
examples:
10-
./cachestat # run with default option of 5 seconds delay
11-
./cachestat -T # run with default option of 5 seconds delay with timestamps
12-
./cachestat 1 # print every second hit/miss stats
13-
./cachestat -T 1 # include timestamps with one second samples
14-
./cachestat 1 5 # run with interval of one second for five iterations
15-
./cachestat -T 1 5 # include timestamps with interval of one second for five iterations
16-
17-
18-
Following commands show a 2GB file being read into the page cache.
19-
20-
Command used to generate activity:
21-
# dd if=/root/tmpfile of=/dev/null bs=8192
22-
23-
Output from cachestat running simultatenously:
24-
# ./tools/cachestat.py 1
25-
TOTAL MISSES HITS DIRTIES BUFFERS_MB CACHED_MB
26-
1 0 1 0 8 283
27-
0 0 0 0 8 283
28-
0 0 0 2 8 283
29-
0 0 0 0 8 283
30-
10009 9173 836 2 9 369
31-
152032 152032 0 0 9 1028
32-
157408 157405 3 0 9 1707
33-
150432 150432 0 0 9 2331
34-
0 0 0 0 9 2331
35-
1 1 0 1 9 2331
36-
0 0 0 0 9 2331
37-
0 0 0 0 9 2331
38-
0 0 0 0 9 2331
39-
40-
The misses counter reflects a 2GB file being read and almost everything being
41-
a page cache miss.
42-
43-
Below shows an example of a new 100MB file added to page cache, by using
44-
the command: dd if=/dev/zero of=/root/tmpfile2 bs=4k count=$((256*100))
45-
46-
# ./tools/cachestat.py 1
47-
TOTAL MISSES HITS DIRTIES BUFFERS_MB CACHED_MB
48-
0 0 0 0 15 2440
49-
0 0 0 0 15 2440
50-
0 0 0 0 15 2440
51-
1758 0 1758 25603 15 2540
52-
0 0 0 0 15 2540
53-
0 0 0 0 15 2541
54-
55-
~25600 pages are being dirtied (writes) which corresponds to the 100MB file
56-
added to the page cache.
90+
-h, --help show this help message and exit
91+
-T, --timestamp include timestamp on output

0 commit comments

Comments
 (0)