1# Measure the performance of PyMutex and PyThread_type_lock locks 2# with short critical sections. 3# 4# Usage: python Tools/lockbench/lockbench.py [CRITICAL_SECTION_LENGTH] 5# 6# How to interpret the results: 7# 8# Acquisitions (kHz): Reports the total number of lock acquisitions in 9# thousands of acquisitions per second. This is the most important metric, 10# particularly for the 1 thread case because even in multithreaded programs, 11# most locks acquisitions are not contended. Values for 2+ threads are 12# only meaningful for `--disable-gil` builds, because the GIL prevents most 13# situations where there is lock contention with short critical sections. 14# 15# Fairness: A measure of how evenly the lock acquisitions are distributed. 16# A fairness of 1.0 means that all threads acquired the lock the same number 17# of times. A fairness of 1/N means that only one thread ever acquired the 18# lock. 19# See https://en.wikipedia.org/wiki/Fairness_measure#Jain's_fairness_index 20 21from _testinternalcapi import benchmark_locks 22import sys 23 24# Max number of threads to test 25MAX_THREADS = 10 26 27# How much "work" to do while holding the lock 28CRITICAL_SECTION_LENGTH = 1 29 30 31def jains_fairness(values): 32 # Jain's fairness index 33 # See https://en.wikipedia.org/wiki/Fairness_measure 34 return (sum(values) ** 2) / (len(values) * sum(x ** 2 for x in values)) 35 36def main(): 37 print("Lock Type Threads Acquisitions (kHz) Fairness") 38 for lock_type in ["PyMutex", "PyThread_type_lock"]: 39 use_pymutex = (lock_type == "PyMutex") 40 for num_threads in range(1, MAX_THREADS + 1): 41 acquisitions, thread_iters = benchmark_locks( 42 num_threads, use_pymutex, CRITICAL_SECTION_LENGTH) 43 44 acquisitions /= 1000 # report in kHz for readability 45 fairness = jains_fairness(thread_iters) 46 47 print(f"{lock_type: <20}{num_threads: <18}{acquisitions: >5.0f}{fairness: >20.2f}") 48 49 50if __name__ == "__main__": 51 if len(sys.argv) > 1: 52 CRITICAL_SECTION_LENGTH = int(sys.argv[1]) 53 main() 54