def benchmarkCacheHit50thKeyKnownSubtype(self): # If there are 50 keys and we get a key that has a subtype in cache and # the cache has observed the key before (to memorize the subtype). cache = function_cache.FunctionCache() args_per_call = 5 num_total_checks = 50 keys = [] for i in range(num_total_checks - 1): args = [] for j in range(args_per_call): args.append(array_ops.zeros([i, j])) keys.append(function_cache.make_cache_key(args)) for key in keys: cache.add(key, "testing") cache.add(MockSubtypeOf2(3), "testing") cache.lookup(MockSubtypeOf2(2), True) iterations = 10000 subtyping_time = timeit.timeit( lambda: cache.lookup(MockSubtypeOf2(2), True), number=iterations) self.report_benchmark(name="cache_hit_50th_key_known_subtype", iters=iterations, wall_time=subtyping_time, metrics=[{ "name": "cache_hit_50th_key_known_subtype_avg_ms", "value": subtyping_time / iterations * 1000 }])
def testWeakRefDeletionAlsoDeletesConcreteFunction(self): dummy_object = DummyClass() key, deletion_observer = function_cache.make_cache_key(dummy_object) cache = function_cache.FunctionCache() cache.add(key, deletion_observer, "testing") self.assertEqual(cache.lookup(key, False), "testing") del dummy_object self.assertIsNone(cache.lookup(key, False))
def testObjectDeletedDuringFunctionCallDoesntAddConcreteFunction(self): def second(o): return function_cache.make_cache_key(o) def first(): return second(DummyClass()) key, deletion_observer = first() cache = function_cache.FunctionCache() cache.add(key, deletion_observer, "testing") self.assertIsNone(cache.lookup(key, False))
def testFirstMostSpecificFunctionCacheKeyIsLookedUp(self): ctx = function_cache.ExecutionContext(1, 1, 1, 1, 1, 1) cache = function_cache.FunctionCache() cache.add(function_cache.FunctionCacheKey(MockShape(1, 2, None), ctx), trace_type.WeakrefDeletionObserver(), "a") cache.add(function_cache.FunctionCacheKey(MockShape(1, None, 3), ctx), trace_type.WeakrefDeletionObserver(), "b") self.assertEqual( cache.lookup( function_cache.FunctionCacheKey(MockShape(1, 2, 3), ctx), True), "a")
def testWeakRefDeletionAlsoDeletesConcreteFunction(self): if not function_cache.DELETE_WITH_WEAKREF: self.skipTest("Weakref-Based Deletion is disabled") dummy_object = DummyClass() key, deletion_observer = function_cache.make_cache_key(dummy_object) cache = function_cache.FunctionCache() cache.add(key, deletion_observer, "testing") self.assertEqual(cache.lookup(key, False), "testing") del dummy_object self.assertIsNone(cache.lookup(key, False))
def testObjectDeletedDuringFunctionCallDoesntAddConcreteFunction(self): if not function_cache.DELETE_WITH_WEAKREF: self.skipTest("Weakref-Based Deletion is disabled") def second(o): return function_cache.make_cache_key(o) def first(): return second(DummyClass()) key, deletion_observer = first() cache = function_cache.FunctionCache() cache.add(key, deletion_observer, "testing") self.assertIsNone(cache.lookup(key, False))
def testExecutionContextSetRetainsInsertedElements(self): cache = function_cache.FunctionCache() ctx_1 = function_cache.ExecutionContext(1, 1, 1, 1, 1, 1) self.assertFalse(cache.has_call_context(ctx_1)) cache.add_call_context(ctx_1) self.assertTrue(cache.has_call_context(ctx_1)) ctx_2 = function_cache.ExecutionContext(1, 1, 1, 1, 1, 1) self.assertTrue(cache.has_call_context(ctx_2)) ctx_3 = function_cache.ExecutionContext(1, 1, 1, 1, 1, None) self.assertFalse(cache.has_call_context(ctx_3)) cache.add_call_context(ctx_3) self.assertTrue(cache.has_call_context(ctx_3))
def testMultipleObjectsWeakRefDeletion(self): dummy_object_1 = DummyClass() dummy_object_2 = DummyClass() key, deletion_observer = function_cache.make_cache_key( (dummy_object_1, dummy_object_2)) cache = function_cache.FunctionCache() cache.add(key, deletion_observer, "testing") self.assertEqual(cache.lookup(key, False), "testing") del dummy_object_1 self.assertIsNone(cache.lookup(key, False)) del dummy_object_2 self.assertIsNone(cache.lookup(key, False))
def testConcreteFunctionDictRetainsInsertedKeys(self): cache = function_cache.FunctionCache() key_1 = function_cache.make_cache_key(1) self.assertIsNone(cache.lookup(key_1, False)) key_2 = function_cache.make_cache_key(2) key_3 = function_cache.make_cache_key(3) cache.add(key_1, "test_1") cache.add(key_2, "test_2") self.assertEqual(cache.lookup(key_1, False), "test_1") self.assertEqual(cache.lookup(key_2, False), "test_2") self.assertIsNone(cache.lookup(key_3, False))
def testDeleteRemovesConcreteFunctions(self): cache = function_cache.FunctionCache() key_1 = function_cache.make_cache_key(1) cache.add(key_1, "test_1") self.assertEqual(cache.lookup(key_1, False), "test_1") cache.delete(key_1) self.assertIsNone(cache.lookup(key_1, False)) key_2 = MockSubtypeOf2(3) cache.add(key_2, "test_2") self.assertEqual(cache.lookup(key_2, False), "test_2") key_3 = MockSubtypeOf2(2) self.assertEqual(cache.lookup(key_3, True), "test_2") cache.delete(key_2) self.assertIsNone(cache.lookup(key_2, False)) self.assertIsNone(cache.lookup(key_3, True))
def testDeleteRemovesConcreteFunctions(self): cache = function_cache.FunctionCache() key_1, deletion_observer_1 = function_cache.make_cache_key(1) cache.add(key_1, deletion_observer_1, "test_1") self.assertEqual(cache.lookup(key_1, False), "test_1") cache.delete(key_1) self.assertIsNone(cache.lookup(key_1, False)) key_2 = function_cache.FunctionCacheKey(MockSubtypeOf2(2), None) cache.add(key_2, trace_type.WeakrefDeletionObserver(), "test_2") self.assertEqual(cache.lookup(key_2, False), "test_2") key_3 = function_cache.FunctionCacheKey(MockSubtypeOf2(3), None) self.assertEqual(cache.lookup(key_3, True), "test_2") cache.delete(key_2) self.assertIsNone(cache.lookup(key_2, False)) self.assertIsNone(cache.lookup(key_3, True))
def testMultipleObjectsWeakRefDeletion(self): if not function_cache.DELETE_WITH_WEAKREF: self.skipTest("Weakref-Based Deletion is disabled") dummy_object_1 = DummyClass() dummy_object_2 = DummyClass() key, deletion_observer = function_cache.make_cache_key( (dummy_object_1, dummy_object_2)) cache = function_cache.FunctionCache() cache.add(key, deletion_observer, "testing") self.assertEqual(cache.lookup(key, False), "testing") del dummy_object_1 self.assertIsNone(cache.lookup(key, False)) del dummy_object_2 self.assertIsNone(cache.lookup(key, False))
def testClearRemovesAllConcreteFunctions(self): cache = function_cache.FunctionCache() key_1 = function_cache.make_cache_key(1) key_2 = function_cache.make_cache_key(2) key_3 = function_cache.make_cache_key(3) cache.add(key_1, "test_1") cache.add(key_2, "test_2") self.assertEqual(cache.lookup(key_1, False), "test_1") self.assertEqual(cache.lookup(key_2, False), "test_2") self.assertIsNone(cache.lookup(key_3, False)) cache.clear() self.assertIsNone(cache.lookup(key_1, False)) self.assertIsNone(cache.lookup(key_2, False)) self.assertIsNone(cache.lookup(key_3, False))
def benchmarkCacheHit50thKeyUnknownSubtype(self): # If there are 50 keys and we get a key that has a subtype in cache but # the cache has never observed the key before (no memory for the subtype). cache = function_cache.FunctionCache() args_per_call = 5 num_total_checks = 50 keys = [] for i in range(num_total_checks - 1): args = [] for j in range(args_per_call): args.append(array_ops.zeros([i, j])) keys.append(function_cache.make_cache_key(args)) def setup(): cache.clear() for key in keys: cache.add(*key, "testing") cache.add( function_cache.FunctionCacheKey(MockSubtypeOf2(3), None), function_trace_type.WeakrefDeletionObserver(), "testing") iterations = 10000 lookup_key = function_cache.FunctionCacheKey(MockSubtypeOf2(2), None) subtyping_time = sum( timeit.repeat( stmt=lambda: cache.lookup(lookup_key, True), setup=setup, repeat=iterations, number=1)) self.report_benchmark( name="cache_hit_50th_key_unknown_subtype", iters=iterations, wall_time=subtyping_time, metrics=[{ "name": "cache_hit_50th_key_unknown_subtype_avg_ms", "value": subtyping_time / iterations * 1000 }])
def benchmarkCacheHit50thKeyEqual(self): # If there are 50 keys and we get a new key that is equal to a key that is # in the cache. cache = function_cache.FunctionCache() args_per_call = 5 num_total_checks = 50 keys = [] for i in range(num_total_checks): args = [] for j in range(args_per_call): args.append(array_ops.zeros([i, j])) keys.append(function_cache.make_cache_key(args)) for key in keys: cache.add(key, "testing") iterations = 10000 subtyping_time = timeit.timeit(lambda: cache.lookup(keys[-1], True), number=iterations) equality_time = timeit.timeit(lambda: cache.lookup(keys[-1], False), number=iterations) self.report_benchmark( name="cache_hit_50th_key_equal", iters=iterations, wall_time=subtyping_time + equality_time, metrics=[{ "name": "cache_hit_50th_key_equal_subtype_avg_ms", "value": subtyping_time / iterations * 1000 }, { "name": "cache_hit_50th_key_equal_equality_avg_ms", "value": equality_time / iterations * 1000 }, { "name": "cache_hit_50th_key_subtype_over_equality_ratio", "value": subtyping_time / equality_time }])
def testMostSpecificFunctionCacheKeyIsOrderAgnostic(self): ctx = function_cache.ExecutionContext(1, 1, 1, 1, 1, 1) keys = [(function_cache.FunctionCacheKey(MockShape(1, 1, 1), ctx), "a"), (function_cache.FunctionCacheKey(MockShape(1, None, 1), ctx), "b"), (function_cache.FunctionCacheKey(MockShape(None, None, 1), ctx), "c"), (function_cache.FunctionCacheKey(MockShape(None, None, None), ctx), "d")] for permutation in itertools.permutations(keys): cache = function_cache.FunctionCache() cache.add(permutation[0][0], trace_type.WeakrefDeletionObserver(), permutation[0][1]) cache.add(permutation[1][0], trace_type.WeakrefDeletionObserver(), permutation[1][1]) cache.add(permutation[2][0], trace_type.WeakrefDeletionObserver(), permutation[2][1]) cache.add(permutation[3][0], trace_type.WeakrefDeletionObserver(), permutation[3][1]) self.assertEqual( cache.lookup( function_cache.FunctionCacheKey(MockShape(1, 1, 1), ctx), True), "a") self.assertEqual( cache.lookup( function_cache.FunctionCacheKey(MockShape(1, 2, 1), ctx), True), "b") self.assertEqual( cache.lookup( function_cache.FunctionCacheKey(MockShape(2, 2, 1), ctx), True), "c") self.assertEqual( cache.lookup( function_cache.FunctionCacheKey(MockShape(2, 2, 2), ctx), True), "d")
def benchmarkCacheHit50thKey(self): # Since FunctionCache uses an OrderedDict, it will check them in the order # of insertion. cache = function_cache.FunctionCache() args_per_call = 5 num_total_checks = 50 keys = [] for i in range(num_total_checks): args = [] for j in range(args_per_call): args.append(array_ops.zeros([i, j])) keys.append(function_cache.make_cache_key(args)) for key in keys: cache.add(key, "testing") iterations = 10000 subtyping_time = timeit.timeit(lambda: cache.lookup(keys[-1], True), number=iterations) equality_time = timeit.timeit(lambda: cache.lookup(keys[-1], False), number=iterations) self.report_benchmark( name="cache_hit_50th_key_subtype", iters=iterations, wall_time=subtyping_time + equality_time, metrics=[{ "name": "cache_hit_50th_key_subtype_avg_ms", "value": subtyping_time / iterations * 1000 }, { "name": "cache_hit_50th_key_equality_avg_ms", "value": equality_time / iterations * 1000 }, { "name": "cache_hit_50th_key_subtype_over_equality_ratio", "value": subtyping_time / equality_time }])