paperDollTests.py (14707B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\paperDoll\paperDollTests.py 2 import itertools 3 import trinity 4 import blue 5 import uthread 6 import weakref 7 import locks 8 import walk 9 from eve.client.script.paperDoll.paperDollImpl import Doll, Factory 10 from eve.client.script.paperDoll.paperDollLOD import LodQueue 11 from eve.client.script.paperDoll.paperDollSpawnWrappers import PaperDollCharacter 12 from eve.common.script.paperDoll.paperDollCommonFunctions import BeFrameNice, Yield 13 from eve.common.script.paperDoll.paperDollConfiguration import PerformanceOptions 14 lock = locks.RLock() 15 DEFAULT_PREPASS_RENDERJOB_NAME = 'RenderTestScene' 16 17 class PerformanceTestResults(dict): 18 19 def __init__(self, iterable = None): 20 dict.__init__(self) 21 if iterable: 22 if type(iterable) == PerformanceTestResults: 23 self.update(iterable) 24 25 def PunchIn(self, key): 26 with lock: 27 self[key] = blue.os.GetWallclockTime() 28 29 def PunchOut(self, key): 30 with lock: 31 self[key] = blue.os.TimeDiffInUs(long(self[key]), blue.os.GetWallclockTime()) / 1000.0 32 33 34 class BenchmarkTest(object): 35 36 def __init__(self): 37 self.testTasklet = None 38 self.factory = None 39 self.scene = None 40 self.usePrepass = False 41 self.results = PerformanceTestResults() 42 43 def _StartTest(self): 44 with lock: 45 self.results.PunchIn('Test execution time') 46 47 def _EndTest(self): 48 with lock: 49 self.results.PunchOut('Test execution time') 50 51 def Execute_t(self, callBack = None): 52 with lock: 53 self._StartTest() 54 self._EndTest() 55 if callBack: 56 uthread.new(callBack) 57 58 def Execute(self, callBack = None): 59 self.results.clear() 60 self.testTasklet = uthread.new(self.Execute_t, callBack) 61 uthread.schedule(self.testTasklet) 62 63 def GetResult(self): 64 return PerformanceTestResults(self.results) 65 66 67 class SingleDollTest(BenchmarkTest): 68 69 def __init__(self, startLOD, endLOD, resPath = None): 70 BenchmarkTest.__init__(self) 71 self.resPath = resPath 72 self.startLOD = startLOD 73 self.endLOD = endLOD 74 self.lodDelta = (endLOD - startLOD) / abs(endLOD - startLOD) if endLOD != startLOD else 0 75 76 def _StartTest(self): 77 BenchmarkTest._StartTest(self) 78 pdc = PaperDollCharacter(self.factory) 79 pdc.doll = Doll('TestDoll') 80 if self.resPath: 81 pdc.doll.Load(self.resPath, self.factory) 82 pdc.doll.overrideLod = self.startLOD 83 spawnKey = 'Spawning doll at LOD {0}'.format(self.startLOD) 84 self.results.PunchIn(spawnKey) 85 pdc.Spawn(self.scene, usePrepass=self.usePrepass) 86 while pdc.doll.busyUpdating: 87 Yield() 88 89 self.results.PunchOut(spawnKey) 90 while pdc.doll.overrideLod != self.endLOD: 91 nextLOD = pdc.doll.overrideLod + self.lodDelta 92 spawnKey = 'Switching from LOD {0} to LOD {1}'.format(pdc.doll.overrideLod, nextLOD) 93 self.results.PunchIn(spawnKey) 94 pdc.doll.overrideLod = nextLOD 95 pdc.Update() 96 while pdc.doll.busyUpdating: 97 Yield() 98 99 self.results.PunchOut(spawnKey) 100 Yield() 101 102 103 class MultiDollTest(BenchmarkTest): 104 105 def __init__(self, numChars = 32, maxLOD0 = 8, maxLOD1 = 16, maxLodQueueActive = None, resPaths = None, debugMode = False): 106 BenchmarkTest.__init__(self) 107 self.debugMode = debugMode 108 self.respathsIterator = itertools.cycle(resPaths) if resPaths else None 109 self.numChars = numChars 110 self.maxLOD0 = maxLOD0 111 self.maxLOD1 = maxLOD1 112 self.maxLOD2 = numChars - (maxLOD0 + maxLOD1) 113 self.maxLodQueueActive = maxLodQueueActive or 1 114 self.paperDollCharacters = [] 115 self.points = [] 116 LodQueue.instance = LodQueue() 117 PerformanceOptions.maxLodQueueActive = self.maxLodQueueActive 118 PerformanceOptions.maxLodQueueActiveUp = self.maxLodQueueActive 119 120 def SpawnDolls(self, lod, count): 121 for i in xrange(count): 122 pdc = PaperDollCharacter(self.factory) 123 pdc.disableDel = self.debugMode 124 pdc.doll = Doll('TestDoll') 125 if self.respathsIterator: 126 spawnKey = 'Loading doll #{0} at LOD {1}'.format(i, lod) 127 self.results.PunchIn(spawnKey) 128 pdc.doll.Load(self.respathsIterator.next(), self.factory) 129 self.results.PunchOut(spawnKey) 130 spawnKey = 'Spawning doll #{0} at LOD {1} without call to Update'.format(i, lod) 131 self.results.PunchIn(spawnKey) 132 pdc.Spawn(self.scene, point=self.points.pop(), lod=99999, updateDoll=False, usePrepass=self.usePrepass) 133 self.results.PunchOut(spawnKey) 134 self.paperDollCharacters.append(pdc) 135 avatar = blue.BluePythonWeakRef(pdc.avatar) 136 doll = weakref.ref(pdc.doll) 137 factory = weakref.ref(pdc.factory) 138 LodQueue.instance.AddToQueue(avatar, doll, factory, lod) 139 140 def _StartTest(self): 141 BenchmarkTest._StartTest(self) 142 self.points = zip(range(self.numChars / 2) * 2, [0] * self.numChars, [0] * (self.numChars / 2) + [1] * (self.numChars / 2)) 143 self.SpawnDolls(0, self.maxLOD0) 144 self.SpawnDolls(1, self.maxLOD1) 145 self.SpawnDolls(2, self.maxLOD2) 146 Yield() 147 while LodQueue.instance.queue: 148 Yield() 149 150 if not self.debugMode: 151 del self.paperDollCharacters[:] 152 153 154 class Benchmarker(object): 155 156 def __init__(self, factory, scene, usePrepass = False, enablePaperDollOptimizations = True): 157 if enablePaperDollOptimizations: 158 PerformanceOptions.EnableOptimizations() 159 self.factory = factory 160 self.scene = scene 161 self.usePrepass = usePrepass 162 self.test = None 163 self.clearCacheOnEachIteration = True 164 self.iterations = 20 165 self.currentIteration = 0 166 self.results = PerformanceTestResults() 167 168 def SetTest(self, test): 169 self.test = test 170 self.currentIteration = 0 171 self.results = PerformanceTestResults() 172 test.factory = self.factory 173 test.scene = self.scene 174 test.usePrepass = self.usePrepass 175 176 def ClearCaches(self): 177 blue.motherLode.ClearCached() 178 179 def ExecuteTest(self, onTestExecution = None): 180 181 def OnTestEnd(): 182 result = self.test.GetResult() 183 self.results[self.currentIteration] = result 184 if self.currentIteration < self.iterations - 1: 185 if onTestExecution: 186 onTestExecution(self.test) 187 if self.clearCacheOnEachIteration: 188 self.ClearCaches() 189 self.test.Execute(callBack=OnTestEnd) 190 self.currentIteration += 1 191 192 if onTestExecution: 193 onTestExecution(self.test) 194 self.results.PunchIn(self.test.__class__) 195 if self.clearCacheOnEachIteration: 196 self.ClearCaches() 197 self.test.Execute(callBack=OnTestEnd) 198 while self.currentIteration < self.iterations - 1: 199 Yield() 200 201 self.results.PunchOut(self.test.__class__) 202 203 def SetAndExecuteTest(self, test): 204 self.SetTest(test) 205 self.ExecuteTest() 206 207 def GetAnalyzedResults(self): 208 statisticalData = {} 209 keys = self.results.keys() 210 for key in keys: 211 if type(key) == int: 212 testIterationResults = self.results[key] 213 for testKey in testIterationResults.keys(): 214 record = statisticalData.get(testKey, []) 215 record.append(testIterationResults[testKey]) 216 statisticalData[testKey] = record 217 218 else: 219 statisticalData[key] = self.results[key] 220 221 for key in statisticalData.keys(): 222 record = statisticalData[key] 223 if type(record) is list: 224 total = sum(record) 225 count = len(record) 226 mean = total / count 227 maxVal = max(record) 228 minVal = min(record) 229 sum2 = sum(((x - mean) ** 2 for x in record)) 230 sum3 = sum((x - mean for x in record)) 231 try: 232 variance = (sum2 - sum3 ** 2 / count) / (count - 1) 233 except ZeroDivisionError: 234 variance = sum2 - sum3 ** 2 / count 235 236 stdDev = variance ** 0.5 237 statisticalData[key] = {'count': count, 238 'total': total, 239 'min': minVal, 240 'max': maxVal, 241 'mean': mean, 242 'variance': variance, 243 'stdDev': stdDev} 244 245 return statisticalData 246 247 248 def CreateEmptyScene(): 249 scene = trinity.Tr2InteriorScene() 250 light1 = trinity.Tr2InteriorLightSource() 251 light1.radius = 100.0 252 light1.position = (0.0, 15.0, 50.0) 253 scene.lights.append(light1) 254 light2 = trinity.Tr2InteriorLightSource() 255 light2.radius = 100.0 256 light2.position = (0.0, 15.0, -50.0) 257 scene.lights.append(light2) 258 light3 = trinity.Tr2InteriorLightSource() 259 light3.radius = 100.0 260 light3.position = (50.0, 15.0, 0.0) 261 scene.lights.append(light3) 262 return scene 263 264 265 def SetupScene(scene = None, sceneFile = None, usePrepass = False): 266 if not sceneFile: 267 scene = CreateEmptyScene() 268 else: 269 scene = blue.resMan.LoadObject(sceneFile) 270 if usePrepass: 271 from trinity.eveSceneRenderJobInterior import CreateEveSceneRenderJobInterior 272 trinity.renderJobs.UnscheduleByName(DEFAULT_PREPASS_RENDERJOB_NAME) 273 rj = CreateEveSceneRenderJobInterior(DEFAULT_PREPASS_RENDERJOB_NAME) 274 scene.shadowUpdatesPerFrame = 0 275 rj.SetScene(scene) 276 rj.CreateBasicRenderSteps() 277 rj.EnableSceneUpdate(True) 278 rj.EnableVisibilityQuery(True) 279 rj.Enable() 280 else: 281 try: 282 scene.enableROIs = True 283 except: 284 pass 285 286 trinity.device.scene = scene 287 return scene 288 289 290 def CollectCharacterSelectionPaths(): 291 respaths = [] 292 for root, dirs, files in walk.walk('res:/graphics/character/dnafiles/characterselect/'): 293 for f in files: 294 respaths.append(root + '/' + f) 295 296 return respaths 297 298 299 def RunCrowdSpawnTest(coldCache = True, iterations = 20, respaths = None, maxLodQueueActive = 1, debugMode = False, nrPerLod = None): 300 301 def fun(): 302 results = PerformanceTestResults() 303 key = 'Loading Factory' 304 results.PunchIn(key) 305 sTime = blue.os.GetWallclockTime() 306 factory = Factory() 307 if respaths: 308 factory.clothSimulationActive = False 309 factory.WaitUntilLoaded() 310 eTime = blue.os.GetWallclockTime() 311 results.PunchOut(key) 312 scene = SetupScene(usePrepass=True) 313 onTestExecution = None 314 try: 315 import pprint 316 bm = Benchmarker(factory, scene, usePrepass=True) 317 bm.clearCacheOnEachIteration = coldCache 318 bm.iterations = 1 if debugMode else iterations 319 totalDolls = sum(nrPerLod) if nrPerLod else 32 320 lod0Dolls = nrPerLod[0] if nrPerLod else 8 321 lod1Dolls = nrPerLod[1] if nrPerLod else 8 322 test0 = MultiDollTest(totalDolls, lod0Dolls, lod1Dolls, maxLodQueueActive=1, resPaths=respaths, debugMode=debugMode) 323 bm.SetTest(test0) 324 bm.ExecuteTest(onTestExecution) 325 pprint.pprint(bm.GetAnalyzedResults()) 326 finally: 327 if not debugMode: 328 trinity.renderJobs.UnscheduleByName(DEFAULT_PREPASS_RENDERJOB_NAME) 329 330 testTasklet = uthread.new(fun) 331 uthread.schedule(testTasklet) 332 try: 333 while testTasklet.alive: 334 Yield() 335 336 except RuntimeError: 337 BeFrameNice() 338 339 340 def RunClothedSpawnTest(coldCache = True, iterations = 20, maxLodQueueActive = 1, debugMode = False): 341 RunCrowdSpawnTest(respaths=CollectCharacterSelectionPaths(), coldCache=coldCache, iterations=iterations, maxLodQueueActive=maxLodQueueActive, debugMode=debugMode) 342 343 344 def RunSymmetricalSingleDollLODTest(coldCache = True, iterations = 20, respaths = None, printStatistics = True): 345 346 def fun(): 347 results = PerformanceTestResults() 348 key = 'Loading Factory' 349 results.PunchIn(key) 350 sTime = blue.os.GetWallclockTime() 351 factory = Factory() 352 if respaths: 353 factory.clothSimulationActive = False 354 factory.WaitUntilLoaded() 355 eTime = blue.os.GetWallclockTime() 356 results.PunchOut(key) 357 scene = SetupScene(usePrepass=True) 358 onTestExecution = None 359 if respaths: 360 respathsIterator = itertools.cycle(respaths) 361 362 def onTestExecution(x): 363 x.resPath = respathsIterator.next() 364 365 try: 366 bm = Benchmarker(factory, scene, usePrepass=True) 367 bm.clearCacheOnEachIteration = coldCache 368 bm.iterations = iterations 369 test0 = SingleDollTest(0, 2) 370 bm.SetTest(test0) 371 bm.ExecuteTest(onTestExecution) 372 if printStatistics: 373 import pprint 374 pprint.pprint(bm.GetAnalyzedResults()) 375 test1 = SingleDollTest(2, 0) 376 bm.SetTest(test1) 377 bm.ExecuteTest(onTestExecution) 378 if printStatistics: 379 pprint.pprint(bm.GetAnalyzedResults()) 380 pprint.pprint(results) 381 finally: 382 trinity.renderJobs.UnscheduleByName(DEFAULT_PREPASS_RENDERJOB_NAME) 383 384 testTasklet = uthread.new(fun) 385 uthread.schedule(testTasklet) 386 try: 387 while testTasklet.alive: 388 Yield() 389 390 except RuntimeError: 391 BeFrameNice() 392 393 394 def RunSymmetricalSingleNudeLODTest(iterations = 20, coldCache = True, printStatistics = True): 395 RunSymmetricalSingleDollLODTest(iterations=iterations, printStatistics=printStatistics) 396 397 398 def RunSymmetricalSingleClothedDollLODTest(iterations = 20, coldCache = True, printStatistics = True): 399 RunSymmetricalSingleDollLODTest(iterations=iterations, respaths=CollectCharacterSelectionPaths(), printStatistics=printStatistics) 400 401 402 def RunComprehensiveSymmetricalDollLODTest(iterations = 20): 403 404 def fun(): 405 RunSymmetricalSingleNudeLODTest(coldCache=True, iterations=iterations) 406 RunSymmetricalSingleClothedDollLODTest(coldCache=True, iterations=iterations) 407 RunSymmetricalSingleNudeLODTest(coldCache=False, iterations=iterations) 408 RunSymmetricalSingleClothedDollLODTest(coldCache=False, iterations=iterations) 409 410 uthread.new(fun)