changeset 27286:528cf1a73ae5

perf: add perflrucachedict command It measures time to construct, perform gets, sets, or mixed mode operations on a cache of configurable size with variable numbers of operations.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sun, 06 Dec 2015 17:07:50 -0800
parents aef5b606d3ee
children c9ceea3f2d8e
files contrib/perf.py tests/test-contrib-perf.t
diffstat 2 files changed, 85 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/perf.py	Sun Dec 06 22:22:09 2015 -0800
+++ b/contrib/perf.py	Sun Dec 06 17:07:50 2015 -0800
@@ -4,6 +4,7 @@
 from mercurial import cmdutil, scmutil, util, commands, obsolete
 from mercurial import repoview, branchmap, merge, copies, error
 import time, os, sys
+import random
 import functools
 
 formatteropts = commands.formatteropts
@@ -582,3 +583,80 @@
     timer, fm = gettimer(ui)
     timer(lambda: len(obsolete.obsstore(repo.svfs)))
     fm.end()
+
+@command('perflrucachedict', formatteropts +
+    [('', 'size', 4, 'size of cache'),
+     ('', 'gets', 10000, 'number of key lookups'),
+     ('', 'sets', 10000, 'number of key sets'),
+     ('', 'mixed', 10000, 'number of mixed mode operations'),
+     ('', 'mixedgetfreq', 50, 'frequency of get vs set ops in mixed mode')],
+    norepo=True)
+def perflrucache(ui, size=4, gets=10000, sets=10000, mixed=10000,
+                 mixedgetfreq=50, **opts):
+    def doinit():
+        for i in xrange(10000):
+            util.lrucachedict(size)
+
+    values = []
+    for i in xrange(size):
+        values.append(random.randint(0, sys.maxint))
+
+    # Get mode fills the cache and tests raw lookup performance with no
+    # eviction.
+    getseq = []
+    for i in xrange(gets):
+        getseq.append(random.choice(values))
+
+    def dogets():
+        d = util.lrucachedict(size)
+        for v in values:
+            d[v] = v
+        for key in getseq:
+            value = d[key]
+            value # silence pyflakes warning
+
+    # Set mode tests insertion speed with cache eviction.
+    setseq = []
+    for i in xrange(sets):
+        setseq.append(random.randint(0, sys.maxint))
+
+    def dosets():
+        d = util.lrucachedict(size)
+        for v in setseq:
+            d[v] = v
+
+    # Mixed mode randomly performs gets and sets with eviction.
+    mixedops = []
+    for i in xrange(mixed):
+        r = random.randint(0, 100)
+        if r < mixedgetfreq:
+            op = 0
+        else:
+            op = 1
+
+        mixedops.append((op, random.randint(0, size * 2)))
+
+    def domixed():
+        d = util.lrucachedict(size)
+
+        for op, v in mixedops:
+            if op == 0:
+                try:
+                    d[v]
+                except KeyError:
+                    pass
+            else:
+                d[v] = v
+
+    benches = [
+        (doinit, 'init'),
+        (dogets, 'gets'),
+        (dosets, 'sets'),
+        (domixed, 'mixed')
+    ]
+
+    for fn, title in benches:
+        timer, fm = gettimer(ui, opts)
+        timer(fn, title=title)
+        fm.end()
+
--- a/tests/test-contrib-perf.t	Sun Dec 06 22:22:09 2015 -0800
+++ b/tests/test-contrib-perf.t	Sun Dec 06 17:07:50 2015 -0800
@@ -75,6 +75,8 @@
                  benchmark the time to parse the on-disk markers for a repo
    perflog       (no help text available)
    perflookup    (no help text available)
+   perflrucachedict
+                 (no help text available)
    perfmanifest  (no help text available)
    perfmergecalculate
                  (no help text available)
@@ -139,6 +141,11 @@
   $ hg perflog 2>&1 | filter_perf_output
   $ hg perflookup 2 2>&1 | filter_perf_output
   ! result: 20
+  $ hg perflrucache 2>&1 | filter_perf_output
+  ! init
+  ! gets
+  ! sets
+  ! mixed
   $ hg perfmanifest 2 2>&1 | filter_perf_output
   $ hg perfmergecalculate -r 3 2>&1 | filter_perf_output
   $ hg perfmoonwalk 2>&1 | filter_perf_output