gh-145685: per-type method cache implementation (#150160) · python/cpython@daf09e1

GitHub

@@ -4,8 +4,10 @@

44fromconcurrent.futuresimportThreadPoolExecutor

55fromthreadingimportBarrier, Thread

66fromunittestimportTestCase

7+importsys

8+fromtest.supportimportimport_helper, threading_helper

798-fromtest.supportimportthreading_helper

10+_testinternalcapi=import_helper.import_module("_testinternalcapi")

91110121113@@ -84,6 +86,24 @@ def reader_func():

84868587self.run_one(writer_func, reader_func)

868889+deftest_attr_cache_mortal(self):

90+classC:

91+x=object()

92+93+classD(C):

94+pass

95+96+defwriter_func():

97+for_inrange(3000):

98+C.x=object()

99+100+defreader_func():

101+for_inrange(3000):

102+C.x

103+D.x

104+105+self.run_one(writer_func, reader_func)

106+87107deftest___class___modification(self):

88108loops=200

89109@@ -160,6 +180,51 @@ def reader():

160180161181self.run_one(writer, reader)

162182183+deftest_per_type_cache_concurrent_reads(self):

184+classC:

185+pass

186+187+names= [sys.intern(f"attr_{i}") foriinrange(

188+_testinternalcapi._Py_TYPECACHE_MINSIZE*4)]

189+fornameinnames:

190+setattr(C, name, name)

191+# Prime the cache.

192+fornameinnames:

193+getattr(C, name)

194+195+lookup=_testinternalcapi.type_cache_lookup

196+197+defreader():

198+for_inrange(500):

199+fornameinnames:

200+hit, value, _=lookup(C, name)

201+self.assertEqual(hit, 1, name)

202+self.assertEqual(value, name)

203+204+threading_helper.run_concurrently(reader, nthreads=NTHREADS)

205+206+deftest_per_type_cache_concurrent_invalidate(self):

207+classC:

208+x="value"

209+210+# Prime the cache.

211+C.x

212+hit, value, version=_testinternalcapi.type_cache_lookup(C, "x")

213+self.assertEqual(hit, 1)

214+self.assertIs(value, "value")

215+self.assertGreater(version, 0)

216+217+defreader():

218+for_inrange(10_000):

219+self.assertIs(C.x, "value")

220+221+definvalidator():

222+for_inrange(10_000):

223+_testinternalcapi.type_cache_invalidate(C)

224+225+workers= [invalidator] + [reader] * (NTHREADS-1)

226+threading_helper.run_concurrently(workers)

227+163228deftest_race_type_attr_added(self):

164229NROUNDS=50

165230NSTOPPERS=4