tests: import fork_histogram.py.
parent
5a96d13fd8
commit
6936b93b43
@ -0,0 +1,92 @@
|
||||
|
||||
# Monkey-patch os.fork() to produce a latency histogram on run completion.
|
||||
# Requires 'hdrhsitograms' PyPI module.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import resource
|
||||
import sys
|
||||
import time
|
||||
|
||||
import ansible.plugins.callback
|
||||
import hdrh.histogram
|
||||
|
||||
|
||||
def get_fault_count(who=resource.RUSAGE_CHILDREN):
|
||||
ru = resource.getrusage(who)
|
||||
return ru.ru_minflt + ru.ru_majflt
|
||||
|
||||
|
||||
class CallbackModule(ansible.plugins.callback.CallbackBase):
|
||||
hist = None
|
||||
|
||||
def v2_playbook_on_start(self, playbook):
|
||||
if self.hist is not None:
|
||||
return
|
||||
|
||||
self.hist = hdrh.histogram.HdrHistogram(1, int(1e6*60), 3)
|
||||
self.fork_latency_sum_usec = 0.0
|
||||
self.install()
|
||||
|
||||
def install(self):
|
||||
self.faults_at_start = get_fault_count(resource.RUSAGE_SELF)
|
||||
self.run_start_time = time.time()
|
||||
self.real_fork = os.fork
|
||||
os.fork = self.my_fork
|
||||
|
||||
self_fault_usec = 1.113664156753052
|
||||
child_fault_usec = 4.734975610975617
|
||||
|
||||
dummy_heap_size = int(os.environ.get('FORK_STATS_FAKE_HEAP_MB', '0'))
|
||||
dummy_heap = 'x' * (dummy_heap_size * 1048576)
|
||||
|
||||
def my_fork(self):
|
||||
# doesnt count last child, oh well
|
||||
now_faults = get_fault_count()
|
||||
t0 = time.time()
|
||||
try:
|
||||
return self.real_fork()
|
||||
finally:
|
||||
latency_usec = (1e6 * (time.time() - t0))
|
||||
self.fork_latency_sum_usec += latency_usec
|
||||
self.hist.record_value(latency_usec)
|
||||
|
||||
def playbook_on_stats(self, stats):
|
||||
self_faults = get_fault_count(resource.RUSAGE_SELF) - self.faults_at_start
|
||||
child_faults = get_fault_count()
|
||||
run_duration_sec = time.time() - self.run_start_time
|
||||
fault_wastage_usec = (
|
||||
((self.self_fault_usec * self_faults) +
|
||||
(self.child_fault_usec * child_faults))
|
||||
)
|
||||
fork_wastage = self.hist.get_total_count()
|
||||
all_wastage_usec = ((2*self.fork_latency_sum_usec) + fault_wastage_usec)
|
||||
|
||||
print('--- Fork statistics ---')
|
||||
print('Post-boot run duration: %.02f ms, %d total forks' % (
|
||||
1000 * run_duration_sec,
|
||||
self.hist.get_total_count(),
|
||||
))
|
||||
print('Self faults during boot: %d, post-boot: %d, avg %d/child' % (
|
||||
self.faults_at_start,
|
||||
self_faults,
|
||||
self_faults / self.hist.get_total_count(),
|
||||
))
|
||||
print('Total child faults: %d, avg %d/child' % (
|
||||
child_faults,
|
||||
child_faults / self.hist.get_total_count(),
|
||||
))
|
||||
print('Est. wastage on faults: %d ms, forks+faults+waits: %d ms (%.2f%%)' % (
|
||||
fault_wastage_usec / 1000,
|
||||
all_wastage_usec / 1000,
|
||||
100 * (all_wastage_usec / (run_duration_sec * 1e6)),
|
||||
))
|
||||
print('99th%% fork latency: %.03f msec, max %d new tasks/sec' % (
|
||||
self.hist.get_value_at_percentile(99) / 1000.0,
|
||||
1e6 / self.hist.get_value_at_percentile(99),
|
||||
))
|
||||
|
||||
self.hist.output_percentile_distribution(sys.stdout, 10)
|
||||
print('--- End fork statistics ---')
|
||||
print()
|
Loading…
Reference in New Issue