]> arthur.barton.de Git - netdata.git/blob - src/proc_spl_kstat_zfs.c
3f5d629228c4bce77cd179fe48766d19b7eec90f
[netdata.git] / src / proc_spl_kstat_zfs.c
1 #include "common.h"
2
3 #define ZFS_PROC_ARCSTATS "/proc/spl/kstat/zfs/arcstats"
4 #define ZFS_FAMILY_SIZE "size"
5 #define ZFS_FAMILY_EFFICIENCY "efficiency"
6 #define ZFS_FAMILY_ACCESSES "accesses"
7 #define ZFS_FAMILY_OPERATIONS "operations"
8 #define ZFS_FAMILY_HASH "hashes"
9
10 static struct arcstats {
11     unsigned long long hits;
12     unsigned long long misses;
13     unsigned long long demand_data_hits;
14     unsigned long long demand_data_misses;
15     unsigned long long demand_metadata_hits;
16     unsigned long long demand_metadata_misses;
17     unsigned long long prefetch_data_hits;
18     unsigned long long prefetch_data_misses;
19     unsigned long long prefetch_metadata_hits;
20     unsigned long long prefetch_metadata_misses;
21     unsigned long long mru_hits;
22     unsigned long long mru_ghost_hits;
23     unsigned long long mfu_hits;
24     unsigned long long mfu_ghost_hits;
25     unsigned long long deleted;
26     unsigned long long mutex_miss;
27     unsigned long long evict_skip;
28     unsigned long long evict_not_enough;
29     unsigned long long evict_l2_cached;
30     unsigned long long evict_l2_eligible;
31     unsigned long long evict_l2_ineligible;
32     unsigned long long evict_l2_skip;
33     unsigned long long hash_elements;
34     unsigned long long hash_elements_max;
35     unsigned long long hash_collisions;
36     unsigned long long hash_chains;
37     unsigned long long hash_chain_max;
38     unsigned long long p;
39     unsigned long long c;
40     unsigned long long c_min;
41     unsigned long long c_max;
42     unsigned long long size;
43     unsigned long long hdr_size;
44     unsigned long long data_size;
45     unsigned long long metadata_size;
46     unsigned long long other_size;
47     unsigned long long anon_size;
48     unsigned long long anon_evictable_data;
49     unsigned long long anon_evictable_metadata;
50     unsigned long long mru_size;
51     unsigned long long mru_evictable_data;
52     unsigned long long mru_evictable_metadata;
53     unsigned long long mru_ghost_size;
54     unsigned long long mru_ghost_evictable_data;
55     unsigned long long mru_ghost_evictable_metadata;
56     unsigned long long mfu_size;
57     unsigned long long mfu_evictable_data;
58     unsigned long long mfu_evictable_metadata;
59     unsigned long long mfu_ghost_size;
60     unsigned long long mfu_ghost_evictable_data;
61     unsigned long long mfu_ghost_evictable_metadata;
62     unsigned long long l2_hits;
63     unsigned long long l2_misses;
64     unsigned long long l2_feeds;
65     unsigned long long l2_rw_clash;
66     unsigned long long l2_read_bytes;
67     unsigned long long l2_write_bytes;
68     unsigned long long l2_writes_sent;
69     unsigned long long l2_writes_done;
70     unsigned long long l2_writes_error;
71     unsigned long long l2_writes_lock_retry;
72     unsigned long long l2_evict_lock_retry;
73     unsigned long long l2_evict_reading;
74     unsigned long long l2_evict_l1cached;
75     unsigned long long l2_free_on_write;
76     unsigned long long l2_cdata_free_on_write;
77     unsigned long long l2_abort_lowmem;
78     unsigned long long l2_cksum_bad;
79     unsigned long long l2_io_error;
80     unsigned long long l2_size;
81     unsigned long long l2_asize;
82     unsigned long long l2_hdr_size;
83     unsigned long long l2_compress_successes;
84     unsigned long long l2_compress_zeros;
85     unsigned long long l2_compress_failures;
86     unsigned long long memory_throttle_count;
87     unsigned long long duplicate_buffers;
88     unsigned long long duplicate_buffers_size;
89     unsigned long long duplicate_reads;
90     unsigned long long memory_direct_count;
91     unsigned long long memory_indirect_count;
92     unsigned long long arc_no_grow;
93     unsigned long long arc_tempreserve;
94     unsigned long long arc_loaned_bytes;
95     unsigned long long arc_prune;
96     unsigned long long arc_meta_used;
97     unsigned long long arc_meta_limit;
98     unsigned long long arc_meta_max;
99     unsigned long long arc_meta_min;
100     unsigned long long arc_need_free;
101     unsigned long long arc_sys_free;
102 } arcstats = { 0 };
103
104 int l2exist = -1;
105
106 static void generate_charts_arcstats(int update_every) {
107
108     // ARC reads
109     unsigned long long aread = arcstats.hits + arcstats.misses;
110
111     // Demand reads
112     unsigned long long dhit = arcstats.demand_data_hits + arcstats.demand_metadata_hits;
113     unsigned long long dmiss = arcstats.demand_data_misses + arcstats.demand_metadata_misses;
114     unsigned long long dread = dhit + dmiss;
115
116     // Prefetch reads
117     unsigned long long phit = arcstats.prefetch_data_hits + arcstats.prefetch_metadata_hits;
118     unsigned long long pmiss = arcstats.prefetch_data_misses + arcstats.prefetch_metadata_misses;
119     unsigned long long pread = phit + pmiss;
120
121     // Metadata reads
122     unsigned long long mhit = arcstats.prefetch_metadata_hits + arcstats.demand_metadata_hits;
123     unsigned long long mmiss = arcstats.prefetch_metadata_misses + arcstats.demand_metadata_misses;
124     unsigned long long mread = mhit + mmiss;
125
126     // l2 reads
127     unsigned long long l2hit = arcstats.l2_hits + arcstats.l2_misses;
128     unsigned long long l2miss = arcstats.prefetch_metadata_misses + arcstats.demand_metadata_misses;
129     unsigned long long l2read = l2hit + l2miss;
130
131     // --------------------------------------------------------------------
132
133     {
134         static RRDSET *st_arc_size = NULL;
135         static RRDDIM *rd_arc_size = NULL;
136         static RRDDIM *rd_arc_target_size = NULL;
137         static RRDDIM *rd_arc_target_min_size = NULL;
138         static RRDDIM *rd_arc_target_max_size = NULL;
139
140         if (unlikely(!st_arc_size)) {
141             st_arc_size = rrdset_create_localhost(
142                     "zfs"
143                     , "arc_size"
144                     , NULL
145                     , ZFS_FAMILY_SIZE
146                     , NULL
147                     , "ZFS ARC Size"
148                     , "MB"
149                     , 2000
150                     , update_every
151                     , RRDSET_TYPE_AREA
152             );
153
154             rd_arc_size            = rrddim_add(st_arc_size, "size",   "arcsz", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
155             rd_arc_target_size     = rrddim_add(st_arc_size, "target", NULL,    1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
156             rd_arc_target_min_size = rrddim_add(st_arc_size, "min",    "min (hard limit)", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
157             rd_arc_target_max_size = rrddim_add(st_arc_size, "max",    "max (high water)", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
158         }
159         else
160             rrdset_next(st_arc_size);
161
162         rrddim_set_by_pointer(st_arc_size, rd_arc_size,            arcstats.size);
163         rrddim_set_by_pointer(st_arc_size, rd_arc_target_size,     arcstats.c);
164         rrddim_set_by_pointer(st_arc_size, rd_arc_target_min_size, arcstats.c_min);
165         rrddim_set_by_pointer(st_arc_size, rd_arc_target_max_size, arcstats.c_max);
166         rrdset_done(st_arc_size);
167     }
168
169     // --------------------------------------------------------------------
170
171     if(likely(l2exist)) {
172         static RRDSET *st_l2_size = NULL;
173         static RRDDIM *rd_l2_size = NULL;
174         static RRDDIM *rd_l2_asize = NULL;
175
176         if (unlikely(!st_l2_size)) {
177             st_l2_size = rrdset_create_localhost(
178                     "zfs"
179                     , "l2_size"
180                     , NULL
181                     , ZFS_FAMILY_SIZE
182                     , NULL
183                     , "ZFS L2 ARC Size"
184                     , "MB"
185                     , 2000
186                     , update_every
187                     , RRDSET_TYPE_AREA
188             );
189
190             rd_l2_asize = rrddim_add(st_l2_size, "actual", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
191             rd_l2_size  = rrddim_add(st_l2_size, "size",   NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
192         }
193         else
194             rrdset_next(st_l2_size);
195
196         rrddim_set_by_pointer(st_l2_size, rd_l2_size,  arcstats.l2_size);
197         rrddim_set_by_pointer(st_l2_size, rd_l2_asize, arcstats.l2_asize);
198         rrdset_done(st_l2_size);
199     }
200
201     // --------------------------------------------------------------------
202
203     {
204         static RRDSET *st_reads = NULL;
205         static RRDDIM *rd_aread = NULL;
206         static RRDDIM *rd_dread = NULL;
207         static RRDDIM *rd_pread = NULL;
208         static RRDDIM *rd_mread = NULL;
209         static RRDDIM *rd_l2read = NULL;
210
211         if (unlikely(!st_reads)) {
212             st_reads = rrdset_create_localhost(
213                     "zfs"
214                     , "reads"
215                     , NULL
216                     , ZFS_FAMILY_ACCESSES
217                     , NULL
218                     , "ZFS Reads"
219                     , "reads/s"
220                     , 2010
221                     , update_every
222                     , RRDSET_TYPE_AREA
223             );
224
225             rd_aread  = rrddim_add(st_reads, "areads",  "arc",      1, 1, RRD_ALGORITHM_INCREMENTAL);
226             rd_dread  = rrddim_add(st_reads, "dreads",  "demand",   1, 1, RRD_ALGORITHM_INCREMENTAL);
227             rd_pread  = rrddim_add(st_reads, "preads",  "prefetch", 1, 1, RRD_ALGORITHM_INCREMENTAL);
228             rd_mread  = rrddim_add(st_reads, "mreads",  "metadata", 1, 1, RRD_ALGORITHM_INCREMENTAL);
229
230             if(l2exist)
231                 rd_l2read = rrddim_add(st_reads, "l2reads", "l2",       1, 1, RRD_ALGORITHM_INCREMENTAL);
232         }
233         else
234             rrdset_next(st_reads);
235
236         rrddim_set_by_pointer(st_reads, rd_aread,  aread);
237         rrddim_set_by_pointer(st_reads, rd_dread,  dread);
238         rrddim_set_by_pointer(st_reads, rd_pread,  pread);
239         rrddim_set_by_pointer(st_reads, rd_mread,  mread);
240
241         if(l2exist)
242             rrddim_set_by_pointer(st_reads, rd_l2read, l2read);
243
244         rrdset_done(st_reads);
245     }
246
247     // --------------------------------------------------------------------
248
249     if(likely(l2exist)) {
250         static RRDSET *st_l2bytes = NULL;
251         static RRDDIM *rd_l2_read_bytes = NULL;
252         static RRDDIM *rd_l2_write_bytes = NULL;
253
254         if (unlikely(!st_l2bytes)) {
255             st_l2bytes = rrdset_create_localhost(
256                     "zfs"
257                     , "bytes"
258                     , NULL
259                     , ZFS_FAMILY_ACCESSES
260                     , NULL
261                     , "ZFS ARC L2 Read/Write Rate"
262                     , "kilobytes/s"
263                     , 2200
264                     , update_every
265                     , RRDSET_TYPE_AREA
266             );
267
268             rd_l2_read_bytes  = rrddim_add(st_l2bytes, "read",  NULL,  1, 1024, RRD_ALGORITHM_INCREMENTAL);
269             rd_l2_write_bytes = rrddim_add(st_l2bytes, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
270         }
271         else
272             rrdset_next(st_l2bytes);
273
274         rrddim_set_by_pointer(st_l2bytes, rd_l2_read_bytes, arcstats.l2_read_bytes);
275         rrddim_set_by_pointer(st_l2bytes, rd_l2_write_bytes, arcstats.l2_write_bytes);
276         rrdset_done(st_l2bytes);
277     }
278
279     // --------------------------------------------------------------------
280
281     {
282         static RRDSET *st_ahits = NULL;
283         static RRDDIM *rd_ahits = NULL;
284         static RRDDIM *rd_amisses = NULL;
285
286         if (unlikely(!st_ahits)) {
287             st_ahits = rrdset_create_localhost(
288                     "zfs"
289                     , "hits"
290                     , NULL
291                     , ZFS_FAMILY_EFFICIENCY
292                     , NULL
293                     , "ZFS ARC Hits"
294                     , "percentage"
295                     , 2020
296                     , update_every
297                     , RRDSET_TYPE_STACKED
298             );
299
300             rd_ahits   = rrddim_add(st_ahits, "hits", NULL,   1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
301             rd_amisses = rrddim_add(st_ahits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
302         }
303         else
304             rrdset_next(st_ahits);
305
306         rrddim_set_by_pointer(st_ahits, rd_ahits,   arcstats.hits);
307         rrddim_set_by_pointer(st_ahits, rd_amisses, arcstats.misses);
308         rrdset_done(st_ahits);
309     }
310
311     // --------------------------------------------------------------------
312
313     {
314         static RRDSET *st_dhits = NULL;
315         static RRDDIM *rd_dhits = NULL;
316         static RRDDIM *rd_dmisses = NULL;
317
318         if (unlikely(!st_dhits)) {
319             st_dhits = rrdset_create_localhost(
320                     "zfs"
321                     , "dhits"
322                     , NULL
323                     , ZFS_FAMILY_EFFICIENCY
324                     , NULL
325                     , "ZFS Demand Hits"
326                     , "percentage"
327                     , 2030
328                     , update_every
329                     , RRDSET_TYPE_STACKED
330             );
331
332             rd_dhits   = rrddim_add(st_dhits, "hits",   NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
333             rd_dmisses = rrddim_add(st_dhits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
334         }
335         else
336             rrdset_next(st_dhits);
337
338         rrddim_set_by_pointer(st_dhits, rd_dhits,   dhit);
339         rrddim_set_by_pointer(st_dhits, rd_dmisses, dmiss);
340         rrdset_done(st_dhits);
341     }
342
343     // --------------------------------------------------------------------
344
345     {
346         static RRDSET *st_phits = NULL;
347         static RRDDIM *rd_phits = NULL;
348         static RRDDIM *rd_pmisses = NULL;
349
350         if (unlikely(!st_phits)) {
351             st_phits = rrdset_create_localhost(
352                     "zfs"
353                     , "phits"
354                     , NULL
355                     , ZFS_FAMILY_EFFICIENCY
356                     , NULL
357                     , "ZFS Prefetch Hits"
358                     , "percentage"
359                     , 2040
360                     , update_every
361                     , RRDSET_TYPE_STACKED
362             );
363
364             rd_phits   = rrddim_add(st_phits, "hits",   NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
365             rd_pmisses = rrddim_add(st_phits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
366         }
367         else
368             rrdset_next(st_phits);
369
370         rrddim_set_by_pointer(st_phits, rd_phits,   phit);
371         rrddim_set_by_pointer(st_phits, rd_pmisses, pmiss);
372         rrdset_done(st_phits);
373     }
374
375     // --------------------------------------------------------------------
376
377     {
378         static RRDSET *st_mhits = NULL;
379         static RRDDIM *rd_mhits = NULL;
380         static RRDDIM *rd_mmisses = NULL;
381
382         if (unlikely(!st_mhits)) {
383             st_mhits = rrdset_create_localhost(
384                     "zfs"
385                     , "mhits"
386                     , NULL
387                     , ZFS_FAMILY_EFFICIENCY
388                     , NULL
389                     , "ZFS Metadata Hits"
390                     , "percentage"
391                     , 2050
392                     , update_every
393                     , RRDSET_TYPE_STACKED
394             );
395
396             rd_mhits   = rrddim_add(st_mhits, "hits",   NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
397             rd_mmisses = rrddim_add(st_mhits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
398         }
399         else
400             rrdset_next(st_mhits);
401
402         rrddim_set_by_pointer(st_mhits, rd_mhits,   mhit);
403         rrddim_set_by_pointer(st_mhits, rd_mmisses, mmiss);
404         rrdset_done(st_mhits);
405     }
406
407     // --------------------------------------------------------------------
408
409     if(likely(l2exist)) {
410         static RRDSET *st_l2hits = NULL;
411         static RRDDIM *rd_l2hits = NULL;
412         static RRDDIM *rd_l2misses = NULL;
413
414         if (unlikely(!st_l2hits)) {
415             st_l2hits = rrdset_create_localhost(
416                     "zfs"
417                     , "l2hits"
418                     , NULL
419                     , ZFS_FAMILY_EFFICIENCY
420                     , NULL
421                     , "ZFS L2 Hits"
422                     , "percentage"
423                     , 2060
424                     , update_every
425                     , RRDSET_TYPE_STACKED
426             );
427
428             rd_l2hits   = rrddim_add(st_l2hits, "hits",   NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
429             rd_l2misses = rrddim_add(st_l2hits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
430         }
431         else
432             rrdset_next(st_l2hits);
433
434         rrddim_set_by_pointer(st_l2hits, rd_l2hits,   l2hit);
435         rrddim_set_by_pointer(st_l2hits, rd_l2misses, l2miss);
436         rrdset_done(st_l2hits);
437     }
438
439     // --------------------------------------------------------------------
440
441     {
442         static RRDSET *st_list_hits = NULL;
443         static RRDDIM *rd_mfu = NULL;
444         static RRDDIM *rd_mru = NULL;
445         static RRDDIM *rd_mfug = NULL;
446         static RRDDIM *rd_mrug = NULL;
447
448         if (unlikely(!st_list_hits)) {
449             st_list_hits = rrdset_create_localhost(
450                     "zfs"
451                     , "list_hits"
452                     , NULL
453                     , ZFS_FAMILY_EFFICIENCY
454                     , NULL
455                     , "ZFS List Hits"
456                     , "hits/s"
457                     , 2100
458                     , update_every
459                     , RRDSET_TYPE_AREA
460             );
461
462             rd_mfu = rrddim_add(st_list_hits,  "mfu",  NULL,        1, 1, RRD_ALGORITHM_INCREMENTAL);
463             rd_mfug = rrddim_add(st_list_hits, "mfug", "mfu ghost", 1, 1, RRD_ALGORITHM_INCREMENTAL);
464             rd_mru = rrddim_add(st_list_hits,  "mru",  NULL,        1, 1, RRD_ALGORITHM_INCREMENTAL);
465             rd_mrug = rrddim_add(st_list_hits, "mrug", "mru ghost", 1, 1, RRD_ALGORITHM_INCREMENTAL);
466         }
467         else
468             rrdset_next(st_list_hits);
469
470         rrddim_set_by_pointer(st_list_hits, rd_mfu, arcstats.mfu_hits);
471         rrddim_set_by_pointer(st_list_hits, rd_mru, arcstats.mru_hits);
472         rrddim_set_by_pointer(st_list_hits, rd_mfug, arcstats.mfu_ghost_hits);
473         rrddim_set_by_pointer(st_list_hits, rd_mrug, arcstats.mru_ghost_hits);
474         rrdset_done(st_list_hits);
475     }
476 }
477
478 static void generate_charts_arc_summary(int update_every) {
479     unsigned long long arc_accesses_total = arcstats.hits + arcstats.misses;
480     unsigned long long real_hits = arcstats.mfu_hits + arcstats.mru_hits;
481     unsigned long long real_misses = arc_accesses_total - real_hits;
482
483     //unsigned long long anon_hits = arcstats.hits - (arcstats.mfu_hits + arcstats.mru_hits + arcstats.mfu_ghost_hits + arcstats.mru_ghost_hits);
484
485     unsigned long long arc_size = arcstats.size;
486     unsigned long long mru_size = arcstats.p;
487     //unsigned long long target_min_size = arcstats.c_min;
488     //unsigned long long target_max_size = arcstats.c_max;
489     unsigned long long target_size = arcstats.c;
490     //unsigned long long target_size_ratio = (target_max_size / target_min_size);
491
492     unsigned long long mfu_size;
493     if(arc_size > target_size)
494         mfu_size = arc_size - mru_size;
495     else
496         mfu_size = target_size - mru_size;
497
498     // --------------------------------------------------------------------
499
500     {
501         static RRDSET *st_arc_size_breakdown = NULL;
502         static RRDDIM *rd_most_recent = NULL;
503         static RRDDIM *rd_most_frequent = NULL;
504
505         if (unlikely(!st_arc_size_breakdown)) {
506             st_arc_size_breakdown = rrdset_create_localhost(
507                     "zfs"
508                     , "arc_size_breakdown"
509                     , NULL
510                     , ZFS_FAMILY_EFFICIENCY
511                     , NULL
512                     , "ZFS ARC Size Breakdown"
513                     , "percentage"
514                     , 2020
515                     , update_every
516                     , RRDSET_TYPE_STACKED
517             );
518
519             rd_most_recent   = rrddim_add(st_arc_size_breakdown, "recent", NULL,   1, 1, RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL);
520             rd_most_frequent = rrddim_add(st_arc_size_breakdown, "frequent", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL);
521         }
522         else
523             rrdset_next(st_arc_size_breakdown);
524
525         rrddim_set_by_pointer(st_arc_size_breakdown, rd_most_recent,   mru_size);
526         rrddim_set_by_pointer(st_arc_size_breakdown, rd_most_frequent, mfu_size);
527         rrdset_done(st_arc_size_breakdown);
528     }
529
530     // --------------------------------------------------------------------
531
532     {
533         static RRDSET *st_memory = NULL;
534         static RRDDIM *rd_direct = NULL;
535         static RRDDIM *rd_throttled = NULL;
536         static RRDDIM *rd_indirect = NULL;
537
538         if (unlikely(!st_memory)) {
539             st_memory = rrdset_create_localhost(
540                     "zfs"
541                     , "memory_ops"
542                     , NULL
543                     , ZFS_FAMILY_OPERATIONS
544                     , NULL
545                     , "ZFS Memory Operations"
546                     , "operations/s"
547                     , 2023
548                     , update_every
549                     , RRDSET_TYPE_LINE
550             );
551
552             rd_direct    = rrddim_add(st_memory, "direct",    NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
553             rd_throttled = rrddim_add(st_memory, "throttled", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
554             rd_indirect  = rrddim_add(st_memory, "indirect",  NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
555         }
556         else
557             rrdset_next(st_memory);
558
559         rrddim_set_by_pointer(st_memory, rd_direct,    arcstats.memory_direct_count);
560         rrddim_set_by_pointer(st_memory, rd_throttled, arcstats.memory_throttle_count);
561         rrddim_set_by_pointer(st_memory, rd_indirect,  arcstats.memory_indirect_count);
562         rrdset_done(st_memory);
563     }
564
565     // --------------------------------------------------------------------
566
567     {
568         static RRDSET *st_important_ops = NULL;
569         static RRDDIM *rd_deleted = NULL;
570         static RRDDIM *rd_mutex_misses = NULL;
571         static RRDDIM *rd_evict_skips = NULL;
572         static RRDDIM *rd_hash_collisions = NULL;
573
574         if (unlikely(!st_important_ops)) {
575             st_important_ops = rrdset_create_localhost(
576                     "zfs"
577                     , "important_ops"
578                     , NULL
579                     , ZFS_FAMILY_OPERATIONS
580                     , NULL
581                     , "ZFS Important Operations"
582                     , "operations/s"
583                     , 2022
584                     , update_every
585                     , RRDSET_TYPE_LINE
586             );
587
588             rd_evict_skips     = rrddim_add(st_important_ops, "eskip",   "evict skip", 1, 1, RRD_ALGORITHM_INCREMENTAL);
589             rd_deleted         = rrddim_add(st_important_ops, "deleted", NULL,         1, 1, RRD_ALGORITHM_INCREMENTAL);
590             rd_mutex_misses    = rrddim_add(st_important_ops, "mtxmis",  "mutex miss", 1, 1, RRD_ALGORITHM_INCREMENTAL);
591             rd_hash_collisions = rrddim_add(st_important_ops, "hash_collisions", "hash collisions", 1, 1, RRD_ALGORITHM_INCREMENTAL);
592         }
593         else
594             rrdset_next(st_important_ops);
595
596         rrddim_set_by_pointer(st_important_ops, rd_deleted,      arcstats.deleted);
597         rrddim_set_by_pointer(st_important_ops, rd_evict_skips,  arcstats.evict_skip);
598         rrddim_set_by_pointer(st_important_ops, rd_mutex_misses, arcstats.mutex_miss);
599         rrddim_set_by_pointer(st_important_ops, rd_hash_collisions, arcstats.hash_collisions);
600         rrdset_done(st_important_ops);
601     }
602
603     // --------------------------------------------------------------------
604
605     {
606         static RRDSET *st_actual_hits = NULL;
607         static RRDDIM *rd_actual_hits = NULL;
608         static RRDDIM *rd_actual_misses = NULL;
609
610         if (unlikely(!st_actual_hits)) {
611             st_actual_hits = rrdset_create_localhost(
612                     "zfs"
613                     , "actual_hits"
614                     , NULL
615                     , ZFS_FAMILY_EFFICIENCY
616                     , NULL
617                     , "ZFS Actual Cache Hits"
618                     , "percentage"
619                     , 2019
620                     , update_every
621                     , RRDSET_TYPE_STACKED
622             );
623
624             rd_actual_hits   = rrddim_add(st_actual_hits, "hits", NULL,   1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
625             rd_actual_misses = rrddim_add(st_actual_hits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
626         }
627         else
628             rrdset_next(st_actual_hits);
629
630         rrddim_set_by_pointer(st_actual_hits, rd_actual_hits,   real_hits);
631         rrddim_set_by_pointer(st_actual_hits, rd_actual_misses, real_misses);
632         rrdset_done(st_actual_hits);
633     }
634
635     // --------------------------------------------------------------------
636
637     {
638         static RRDSET *st_demand_data_hits = NULL;
639         static RRDDIM *rd_demand_data_hits = NULL;
640         static RRDDIM *rd_demand_data_misses = NULL;
641
642         if (unlikely(!st_demand_data_hits)) {
643             st_demand_data_hits = rrdset_create_localhost(
644                     "zfs"
645                     , "demand_data_hits"
646                     , NULL
647                     , ZFS_FAMILY_EFFICIENCY
648                     , NULL
649                     , "ZFS Data Demand Efficiency"
650                     , "percentage"
651                     , 2031
652                     , update_every
653                     , RRDSET_TYPE_STACKED
654             );
655
656             rd_demand_data_hits   = rrddim_add(st_demand_data_hits, "hits", NULL,   1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
657             rd_demand_data_misses = rrddim_add(st_demand_data_hits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
658         }
659         else
660             rrdset_next(st_demand_data_hits);
661
662         rrddim_set_by_pointer(st_demand_data_hits, rd_demand_data_hits,   arcstats.demand_data_hits);
663         rrddim_set_by_pointer(st_demand_data_hits, rd_demand_data_misses, arcstats.demand_data_misses);
664         rrdset_done(st_demand_data_hits);
665     }
666
667     // --------------------------------------------------------------------
668
669     {
670         static RRDSET *st_prefetch_data_hits = NULL;
671         static RRDDIM *rd_prefetch_data_hits = NULL;
672         static RRDDIM *rd_prefetch_data_misses = NULL;
673
674         if (unlikely(!st_prefetch_data_hits)) {
675             st_prefetch_data_hits = rrdset_create_localhost(
676                     "zfs"
677                     , "prefetch_data_hits"
678                     , NULL
679                     , ZFS_FAMILY_EFFICIENCY
680                     , NULL
681                     , "ZFS Data Prefetch Efficiency"
682                     , "percentage"
683                     , 2032
684                     , update_every
685                     , RRDSET_TYPE_STACKED
686             );
687
688             rd_prefetch_data_hits   = rrddim_add(st_prefetch_data_hits, "hits", NULL,   1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
689             rd_prefetch_data_misses = rrddim_add(st_prefetch_data_hits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
690         }
691         else
692             rrdset_next(st_prefetch_data_hits);
693
694         rrddim_set_by_pointer(st_prefetch_data_hits, rd_prefetch_data_hits,   arcstats.prefetch_data_hits);
695         rrddim_set_by_pointer(st_prefetch_data_hits, rd_prefetch_data_misses, arcstats.prefetch_data_misses);
696         rrdset_done(st_prefetch_data_hits);
697     }
698
699     // --------------------------------------------------------------------
700
701     {
702         static RRDSET *st_hash_elements = NULL;
703         static RRDDIM *rd_hash_elements_current = NULL;
704         static RRDDIM *rd_hash_elements_max = NULL;
705
706         if (unlikely(!st_hash_elements)) {
707             st_hash_elements = rrdset_create_localhost(
708                     "zfs"
709                     , "hash_elements"
710                     , NULL
711                     , ZFS_FAMILY_HASH
712                     , NULL
713                     , "ZFS ARC Hash Elements"
714                     , "elements"
715                     , 2300
716                     , update_every
717                     , RRDSET_TYPE_LINE
718             );
719
720             rd_hash_elements_current = rrddim_add(st_hash_elements, "current", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
721             rd_hash_elements_max     = rrddim_add(st_hash_elements, "max",     NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
722         }
723         else
724             rrdset_next(st_hash_elements);
725
726         rrddim_set_by_pointer(st_hash_elements, rd_hash_elements_current, arcstats.hash_elements);
727         rrddim_set_by_pointer(st_hash_elements, rd_hash_elements_max, arcstats.hash_elements_max);
728         rrdset_done(st_hash_elements);
729     }
730
731     // --------------------------------------------------------------------
732
733     {
734         static RRDSET *st_hash_chains = NULL;
735         static RRDDIM *rd_hash_chains_current = NULL;
736         static RRDDIM *rd_hash_chains_max = NULL;
737
738         if (unlikely(!st_hash_chains)) {
739             st_hash_chains = rrdset_create_localhost(
740                     "zfs"
741                     , "hash_chains"
742                     , NULL
743                     , ZFS_FAMILY_HASH
744                     , NULL
745                     , "ZFS ARC Hash Chains"
746                     , "chains"
747                     , 2310
748                     , update_every
749                     , RRDSET_TYPE_LINE
750             );
751
752             rd_hash_chains_current = rrddim_add(st_hash_chains, "current", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
753             rd_hash_chains_max     = rrddim_add(st_hash_chains, "max",     NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
754         }
755         else
756             rrdset_next(st_hash_chains);
757
758         rrddim_set_by_pointer(st_hash_chains, rd_hash_chains_current, arcstats.hash_chains);
759         rrddim_set_by_pointer(st_hash_chains, rd_hash_chains_max, arcstats.hash_chain_max);
760         rrdset_done(st_hash_chains);
761     }
762
763     // --------------------------------------------------------------------
764
765 }
766
767 int do_proc_spl_kstat_zfs_arcstats(int update_every, usec_t dt) {
768     (void)dt;
769
770     static procfile *ff = NULL;
771     static ARL_BASE *arl_base = NULL;
772
773     if(unlikely(!arl_base)) {
774         arl_base = arl_create("arcstats", NULL, 60);
775
776         arl_expect(arl_base, "hits", &arcstats.hits);
777         arl_expect(arl_base, "misses", &arcstats.misses);
778         arl_expect(arl_base, "demand_data_hits", &arcstats.demand_data_hits);
779         arl_expect(arl_base, "demand_data_misses", &arcstats.demand_data_misses);
780         arl_expect(arl_base, "demand_metadata_hits", &arcstats.demand_metadata_hits);
781         arl_expect(arl_base, "demand_metadata_misses", &arcstats.demand_metadata_misses);
782         arl_expect(arl_base, "prefetch_data_hits", &arcstats.prefetch_data_hits);
783         arl_expect(arl_base, "prefetch_data_misses", &arcstats.prefetch_data_misses);
784         arl_expect(arl_base, "prefetch_metadata_hits", &arcstats.prefetch_metadata_hits);
785         arl_expect(arl_base, "prefetch_metadata_misses", &arcstats.prefetch_metadata_misses);
786         arl_expect(arl_base, "mru_hits", &arcstats.mru_hits);
787         arl_expect(arl_base, "mru_ghost_hits", &arcstats.mru_ghost_hits);
788         arl_expect(arl_base, "mfu_hits", &arcstats.mfu_hits);
789         arl_expect(arl_base, "mfu_ghost_hits", &arcstats.mfu_ghost_hits);
790         arl_expect(arl_base, "deleted", &arcstats.deleted);
791         arl_expect(arl_base, "mutex_miss", &arcstats.mutex_miss);
792         arl_expect(arl_base, "evict_skip", &arcstats.evict_skip);
793         arl_expect(arl_base, "evict_not_enough", &arcstats.evict_not_enough);
794         arl_expect(arl_base, "evict_l2_cached", &arcstats.evict_l2_cached);
795         arl_expect(arl_base, "evict_l2_eligible", &arcstats.evict_l2_eligible);
796         arl_expect(arl_base, "evict_l2_ineligible", &arcstats.evict_l2_ineligible);
797         arl_expect(arl_base, "evict_l2_skip", &arcstats.evict_l2_skip);
798         arl_expect(arl_base, "hash_elements", &arcstats.hash_elements);
799         arl_expect(arl_base, "hash_elements_max", &arcstats.hash_elements_max);
800         arl_expect(arl_base, "hash_collisions", &arcstats.hash_collisions);
801         arl_expect(arl_base, "hash_chains", &arcstats.hash_chains);
802         arl_expect(arl_base, "hash_chain_max", &arcstats.hash_chain_max);
803         arl_expect(arl_base, "p", &arcstats.p);
804         arl_expect(arl_base, "c", &arcstats.c);
805         arl_expect(arl_base, "c_min", &arcstats.c_min);
806         arl_expect(arl_base, "c_max", &arcstats.c_max);
807         arl_expect(arl_base, "size", &arcstats.size);
808         arl_expect(arl_base, "hdr_size", &arcstats.hdr_size);
809         arl_expect(arl_base, "data_size", &arcstats.data_size);
810         arl_expect(arl_base, "metadata_size", &arcstats.metadata_size);
811         arl_expect(arl_base, "other_size", &arcstats.other_size);
812         arl_expect(arl_base, "anon_size", &arcstats.anon_size);
813         arl_expect(arl_base, "anon_evictable_data", &arcstats.anon_evictable_data);
814         arl_expect(arl_base, "anon_evictable_metadata", &arcstats.anon_evictable_metadata);
815         arl_expect(arl_base, "mru_size", &arcstats.mru_size);
816         arl_expect(arl_base, "mru_evictable_data", &arcstats.mru_evictable_data);
817         arl_expect(arl_base, "mru_evictable_metadata", &arcstats.mru_evictable_metadata);
818         arl_expect(arl_base, "mru_ghost_size", &arcstats.mru_ghost_size);
819         arl_expect(arl_base, "mru_ghost_evictable_data", &arcstats.mru_ghost_evictable_data);
820         arl_expect(arl_base, "mru_ghost_evictable_metadata", &arcstats.mru_ghost_evictable_metadata);
821         arl_expect(arl_base, "mfu_size", &arcstats.mfu_size);
822         arl_expect(arl_base, "mfu_evictable_data", &arcstats.mfu_evictable_data);
823         arl_expect(arl_base, "mfu_evictable_metadata", &arcstats.mfu_evictable_metadata);
824         arl_expect(arl_base, "mfu_ghost_size", &arcstats.mfu_ghost_size);
825         arl_expect(arl_base, "mfu_ghost_evictable_data", &arcstats.mfu_ghost_evictable_data);
826         arl_expect(arl_base, "mfu_ghost_evictable_metadata", &arcstats.mfu_ghost_evictable_metadata);
827         arl_expect(arl_base, "l2_hits", &arcstats.l2_hits);
828         arl_expect(arl_base, "l2_misses", &arcstats.l2_misses);
829         arl_expect(arl_base, "l2_feeds", &arcstats.l2_feeds);
830         arl_expect(arl_base, "l2_rw_clash", &arcstats.l2_rw_clash);
831         arl_expect(arl_base, "l2_read_bytes", &arcstats.l2_read_bytes);
832         arl_expect(arl_base, "l2_write_bytes", &arcstats.l2_write_bytes);
833         arl_expect(arl_base, "l2_writes_sent", &arcstats.l2_writes_sent);
834         arl_expect(arl_base, "l2_writes_done", &arcstats.l2_writes_done);
835         arl_expect(arl_base, "l2_writes_error", &arcstats.l2_writes_error);
836         arl_expect(arl_base, "l2_writes_lock_retry", &arcstats.l2_writes_lock_retry);
837         arl_expect(arl_base, "l2_evict_lock_retry", &arcstats.l2_evict_lock_retry);
838         arl_expect(arl_base, "l2_evict_reading", &arcstats.l2_evict_reading);
839         arl_expect(arl_base, "l2_evict_l1cached", &arcstats.l2_evict_l1cached);
840         arl_expect(arl_base, "l2_free_on_write", &arcstats.l2_free_on_write);
841         arl_expect(arl_base, "l2_cdata_free_on_write", &arcstats.l2_cdata_free_on_write);
842         arl_expect(arl_base, "l2_abort_lowmem", &arcstats.l2_abort_lowmem);
843         arl_expect(arl_base, "l2_cksum_bad", &arcstats.l2_cksum_bad);
844         arl_expect(arl_base, "l2_io_error", &arcstats.l2_io_error);
845         arl_expect(arl_base, "l2_size", &arcstats.l2_size);
846         arl_expect(arl_base, "l2_asize", &arcstats.l2_asize);
847         arl_expect(arl_base, "l2_hdr_size", &arcstats.l2_hdr_size);
848         arl_expect(arl_base, "l2_compress_successes", &arcstats.l2_compress_successes);
849         arl_expect(arl_base, "l2_compress_zeros", &arcstats.l2_compress_zeros);
850         arl_expect(arl_base, "l2_compress_failures", &arcstats.l2_compress_failures);
851         arl_expect(arl_base, "memory_throttle_count", &arcstats.memory_throttle_count);
852         arl_expect(arl_base, "duplicate_buffers", &arcstats.duplicate_buffers);
853         arl_expect(arl_base, "duplicate_buffers_size", &arcstats.duplicate_buffers_size);
854         arl_expect(arl_base, "duplicate_reads", &arcstats.duplicate_reads);
855         arl_expect(arl_base, "memory_direct_count", &arcstats.memory_direct_count);
856         arl_expect(arl_base, "memory_indirect_count", &arcstats.memory_indirect_count);
857         arl_expect(arl_base, "arc_no_grow", &arcstats.arc_no_grow);
858         arl_expect(arl_base, "arc_tempreserve", &arcstats.arc_tempreserve);
859         arl_expect(arl_base, "arc_loaned_bytes", &arcstats.arc_loaned_bytes);
860         arl_expect(arl_base, "arc_prune", &arcstats.arc_prune);
861         arl_expect(arl_base, "arc_meta_used", &arcstats.arc_meta_used);
862         arl_expect(arl_base, "arc_meta_limit", &arcstats.arc_meta_limit);
863         arl_expect(arl_base, "arc_meta_max", &arcstats.arc_meta_max);
864         arl_expect(arl_base, "arc_meta_min", &arcstats.arc_meta_min);
865         arl_expect(arl_base, "arc_need_free", &arcstats.arc_need_free);
866         arl_expect(arl_base, "arc_sys_free", &arcstats.arc_sys_free);
867     }
868
869     if(unlikely(!ff)) {
870         char filename[FILENAME_MAX + 1];
871         snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, ZFS_PROC_ARCSTATS);
872         ff = procfile_open(config_get("plugin:proc:" ZFS_PROC_ARCSTATS, "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
873         if(unlikely(!ff))
874             return 1;
875     }
876
877     ff = procfile_readall(ff);
878     if(unlikely(!ff))
879         return 0; // we return 0, so that we will retry to open it next time
880
881     size_t lines = procfile_lines(ff), l;
882
883     arl_begin(arl_base);
884
885     for(l = 0; l < lines ;l++) {
886         size_t words = procfile_linewords(ff, l);
887         if(unlikely(words < 3)) {
888             if(unlikely(words)) error("Cannot read " ZFS_PROC_ARCSTATS " line %zu. Expected 3 params, read %zu.", l, words);
889             continue;
890         }
891
892         const char *key   = procfile_lineword(ff, l, 0);
893         const char *value = procfile_lineword(ff, l, 2);
894
895         if(unlikely(l2exist == -1)) {
896             if(key[0] == 'l' && key[1] == '2' && key[2] == '_')
897                 l2exist = 1;
898         }
899
900         if(unlikely(arl_check(arl_base, key, value))) break;
901     }
902
903     if(unlikely(l2exist == -1))
904         l2exist = 0;
905
906     generate_charts_arcstats(update_every);
907     generate_charts_arc_summary(update_every);
908
909     return 0;
910 }