Dtrace kernel and userspace memory activity
#!/usr/sbin/dtrace -s
#pragma D option flowindent
:::BEGIN
{
start = timestamp;
}
syscall:::
/$target == pid/
{
trace((timestamp - start) / 1000);
}
fbt:unix:page*:,
::add_physmem:,
::anon_alloc:,
::anon_array_enter:,
::anon_array_exit:,
::anon_copy_ptr:,
::anon_create:,
::anon_decref:,
::anon_disclaim:,
::anon_dup:,
::anon_dup_fill_holes:,
::anon_free:,
::anon_free_pages:,
::anon_get_next_ptr:,
::anon_get_slot:,
::anon_getpage:,
::anon_grow:,
::anon_init:,
::anon_map_createpages:,
::anon_map_demotepages:,
::anon_map_getpages:,
::anon_pages:,
::anon_private:,
::anon_release:,
::anon_resvmem:,
::anon_set_ptr:,
::anon_swap_adjust:,
::anon_swap_restore:,
::anon_unresvmem:,
::anon_zero:,
::anonmap_alloc:,
::anonmap_free:,
::as_add_callback:,
::as_addseg:,
::as_alloc:,
::as_avlinit:,
::as_checkprot:,
::as_clearwatch:,
::as_ctl:,
::as_delete_callback:,
::as_dup:,
::as_execute_callback:,
::as_fault:,
::as_faulta:,
::as_findseg:,
::as_free:,
::as_gap:,
::as_getmemid:,
::as_incore:,
::as_init:,
::as_map:,
::as_memory:,
::as_pagelock:,
::as_pagelock_segs:,
::as_pageunlock:,
::as_pageunlock_segs:,
::as_purge:,
::as_rangelock:,
::as_rangeunlock:,
::as_removeseg:,
::as_segat:,
::as_setpagesize:,
::as_setprot:,
::as_setwatch:,
::as_signal_proc:,
::as_swapout:,
::as_unmap:,
::boot_alloc:,
::boot_mapin:,
::build_pfn_hash:,
::do_page_relocate:,
::free_vp_pages:,
::get_free_smp:,
::hat_alloc:,
::hat_chgattr:,
::hat_chgprot:,
::hat_clrattr:,
::hat_devload:,
::hat_dump:,
::hat_enter:,
::hat_exit:,
::hat_free_end:,
::hat_free_start:,
::hat_freestat:,
::hat_getattr:,
::hat_getpagesize:,
::hat_getpfnum:,
::hat_getstat:,
::hat_init:,
::hat_kpm_fault:,
::hat_kpm_mapin:,
::hat_memload:,
::hat_memload_array:,
::hat_page_clrattr:,
::hat_page_getshare:,
::hat_page_setattr:,
::hat_pagesync:,
::hat_pageunload:,
::hat_probe:,
::hat_resvstat:,
::hat_setattr:,
::hat_setstat:,
::hat_setup:,
::hat_share:,
::hat_startstat:,
::hat_stats_disable:,
::hat_stats_enable:,
::hat_supported:,
::hat_swapout:,
::hat_sync:,
::hat_thread_exit:,
::hat_unload:,
::hat_unload_callback:,
::hat_unlock:,
::hat_unshare:,
::kernelheap_init:,
::non_anon:,
::page_add:,
::page_addclaim:,
::page_addclaim_pages:,
::page_boot_demote:,
::page_busy:,
::page_clrtoxic:,
::page_create:,
::page_create_putback:,
::page_create_va:,
::page_create_va_large:,
::page_create_wait:,
::page_demote_free_pages:,
::page_destroy:,
::page_destroy_free:,
::page_destroy_pages:,
::page_downgrade:,
::page_exists_forreal:,
::page_find:,
::page_free:,
::page_free_at_startup:,
::page_free_pages:,
::page_free_replacement_page:,
::page_get_cachelist:,
::page_get_freelist:,
::page_get_pagecnt:,
::page_get_pagesize:,
::page_get_replacement_page:,
::page_hashin:,
::page_hashout:,
::page_io_lock:,
::page_io_trylock:,
::page_io_unlock:,
::page_iolock_init:,
::page_ismod:,
::page_isref:,
::page_isshared:,
::page_list_add:,
::page_list_add_pages:,
::page_list_sub:,
::page_lock:,
::page_lock_clr_exclwanted:,
::page_lock_delete:,
::page_lookup:,
::page_lookup_create:,
::page_lookup_nowait:,
::page_mark_migrate:,
::page_mem_config*:,
::page_migrate:,
::page_needfree:,
::page_next:,
::page_next_scan_large:,
::page_numtopp:,
::page_numtopp_noreclaim:,
::page_numtopp_nowait:,
::page_pp_lock:,
::page_pp_unlock:,
::page_pp_useclaim:,
::page_promote_size:,
::page_release:,
::page_relocate:,
::page_relocate_cage:,
::page_relocate_hash:,
::page_rename:,
::page_resv:,
::page_retire:,
::page_settoxic:,
::page_share_cnt:,
::page_sub:,
::page_subclaim:,
::page_subclaim_pages:,
::page_try_demote_pages:,
::page_try_reclaim_lock:,
::page_trylock:,
::page_tryupgrade:,
::page_unlock:,
::page_unresv:,
::page_vpsub:,
::pagezero:,
::ppcopy:,
::pvn_getdirty:,
::pvn_getpages:,
::pvn_init:,
::pvn_io_done:,
::pvn_plist_init:,
::pvn_read_done:,
::pvn_read_kluster:,
::pvn_vplist_dirty:,
::pvn_vpzero:,
::pvn_write_done:,
::pvn_write_kluster:,
::rm_asrss:,
::rm_pctmemory:,
::seg_alloc:,
::seg_attach:,
::seg_free:,
::seg_init:,
::seg_pasync_thread:,
::seg_pinactive:,
::seg_pinsert:,
::seg_plookup:,
::seg_ppurge*:,
::seg_preap:,
::seg_unmap:,
::segdev_checkprot:,
::segdev_copyfrom:,
::segdev_copyto:,
::segdev_create:,
::segdev_dup:,
::segdev_fault:,
::segdev_free:,
::segdev_getprot:,
::segdev_setprot:,
::segdev_unmap:,
::segkmem_alloc:,
::segkmem_free:,
::segkmem_gc:,
::segkmem_page_create:,
::segkmem_xalloc:,
::segkp_cache_free:,
::segkp_cache_get:,
::segkp_cache_init:,
::segkp_checkprot:,
::segkp_create:,
::segkp_dump:,
::segkp_fault:,
::segkp_get:,
::segkp_get_withanonmap:,
::segkp_map_red:,
::segkp_release:,
::segkp_unmap_red:,
::segkpm_create:,
::segkpm_create_va:,
::segkpm_fault:,
::segkpm_mapout_validkpme:,
::segmap_create:,
::segmap_dump:,
::segmap_fault:,
::segmap_faulta:,
::segmap_getmap:,
::segmap_getmapflt:,
::segmap_pagecreate:,
::segmap_pageunlock:,
::segmap_release:,
::segspt_free:,
::segspt_shmattach:,
::segspt_unmap:,
::segvn_advise:,
::segvn_checkprot:,
::segvn_create:,
::segvn_dump:,
::segvn_dup:,
::segvn_fault:,
::segvn_faulta:,
::segvn_free:,
::segvn_getmemid:,
::segvn_getprot:,
::segvn_incore:,
::segvn_init:,
::segvn_kluster:,
::segvn_lockop:,
::segvn_pagelock:,
::segvn_setpagesize:,
::segvn_setprot:,
::segvn_swapout:,
::segvn_sync:,
::segvn_unmap:,
::sptcreate:,
::sptdestroy:,
::swap_getconpage:,
::swapsize:,
::va_to_pfn:
/$target == pid/
{
trace((timestamp - start) / 1000);
}
dtrace -qn '
page_create_throttle:return {
@[execname, caller] = count();
happened = 1 ;
}
tick-10sec /happened/ {
printa("prog: %s caller: %a count: %@d\n", @); trunc(@);
happened = 0 ;
}'
dtrace -n '
::arc_kmem_reap_now:entry {
in_kmr = 1;
bufsz = 0;
self->start = timestamp;
}
::kmem_cache_reap_now:entry /in_kmr/ {
bufsz += args[0]->cache_buftotal;
}
::arc_kmem_reap_now:return /in_kmr/ {
this->delta = (timestamp - self->start) / 1000000;
@r[this->delta] = sum(bufsz);
self->timestamp = 0;
in_kmr = 0;
printf("%Y,", walltimestamp); printa("%d,%@d\n", @r);
trunc(@r);
}'
dtrace -qn '
tick-1sec {
ts = walltimestamp
}
/* Sum-up bytes being freed during `ts` interval */
::kmem_free:entry /ts/ {
@[ts] = sum(args[1]);
} tick-5sec {
printa("%Y,%@d\n", @); trunc(@);
}'
dtrace -qn '
/*
* Measure with a 1-second reporting interval number of times
* kernel memory allocations happen for "X" process,
* via kmem_alloc and kmem_zalloc, and sum total bytes,
* reporting in Kilobytes. This effectively results in
* per second count, with a per second sum of bytes allocated.
* first argument after this script will be name of something
* like a process (e.g. "nfsd"), with which allocations are associated.
*/
BEGIN {
printf("timestamp,count,Kbytes\n");
}
tick-1sec {
ts = walltimestamp;
}
::kmem_alloc:entry,
::kmem_zalloc:entry /execname==$$1 && ts > 0/ {
@sum[ts] = sum(arg0);
@cnt[ts] = count();
}
tick-5sec {
normalize(@sum, 1024);
printa("%Y,%@d,%@d\n", @cnt,@sum);
trunc(@cnt); trunc(@sum);
}'
dtrace -qn '
BEGIN {
printf("timestamp,count,mean.bytes,sum.Kbytes\n");
}
::kmem_free:entry {
@s = sum(args[1]);
@cnt = count();
@mean = avg(args[1]);
}
tick-1sec {
normalize(@s, 1024);
printf("%Y,", walltimestamp);
printa("%@d,%@d,%@d\n", @cnt, @mean, @s);
trunc(@s); trunc(@cnt); trunc(@mean);
}'
dtrace -qn '::kmem_reap_start:entry {self->ts = timestamp} ::kmem_reap_start:return {@ = quantize(timestamp - self->ts);} tick-5sec {printa(@); trunc(@);}'
dtrace -qn '
inline const int KM_SLEEP = 0 ;
kmem_cache_alloc:entry,
kmem_alloc:entry,
kmem_zalloc:entry
/args[1] == KM_SLEEP/ {
self->c = caller ;
self->ts = timestamp ;
}
kmem_cache_alloc:return,
kmem_alloc:return,
kmem_zalloc:return /self->c/ {
@lat[caller, probefunc] = quantize(timestamp - self->ts);
@avlat[caller, probefunc] = avg(timestamp - self->ts);
@[caller, probefunc] = count();
self->c = 0 ; self->ts = 0 ;
}
END {
printa("[%@d] caller: %a probe: %s Av_lat(nsec): %@d\n\t Latency(nsec):%@d\n",
@, @avlat, @lat);
}'
dtrace -qn '
/* Measure cache allocation duration. We are looking for outliers here. */
BEGIN {
ts = walltimestamp;
printf("avg.lat,stddev.lat,min.lat,max.lat,count.allocs\n");
}
::kmem_cache_alloc:entry /ts/ {
self->ts = timestamp;
}
::kmem_cache_alloc:return {
this->delta = (timestamp - self->ts);
@cnt[ts] = count();
@minlat[ts] = min(this->delta);
@maxlat[ts] = max(this->delta);
@sdlat[ts] = stddev(this->delta);
@avglat[ts] = avg(this->delta);
}
tick-1sec {
printa("%Y,%@d,%@d,%@d,%@d,%@d\n",
@avglat,@sdlat,@minlat,@maxlat,@cnt);
trunc(@avglat); trunc(@sdlat);
trunc(@minlat); trunc(@maxlat); trunc(@cnt);
ts = walltimestamp;
}'
// How much memory is available to ARC. If value is negative, ARC is likely being
// shrunk due to demand by system.
dtrace -qn '
BEGIN {
printf("timestamp,avail.memory\n");
wait = 0;
}
::arc_available_memory:return /wait == 0/ {
printf("%Y,%d\n", walltimestamp, args[1]);
++wait;
}
tick-1sec /wait/ {
wait = 0;
}'