浏览代码

Added ability to repeat performance tests

Jorrit Rouwe 2 年之前
父节点
当前提交
dbd57cb360
共有 1 个文件被更改,包括 172 次插入161 次删除
  1. 172 161
      PerformanceTest/PerformanceTest.cpp

+ 172 - 161
PerformanceTest/PerformanceTest.cpp

@@ -73,6 +73,7 @@ int main(int argc, char** argv)
 	bool validate_state = false;
 	unique_ptr<PerformanceTestScene> scene;
 	const char *validate_hash = nullptr;
+	int repeat = 1;
 	for (int argidx = 1; argidx < argc; ++argidx)
 	{
 		const char *arg = argv[argidx];
@@ -143,6 +144,11 @@ int main(int argc, char** argv)
 		{
 			validate_hash = arg + 15;
 		}
+		else if (strncmp(arg, "-repeat=", 8) == 0)
+		{
+			// Parse repeat count
+			repeat = atoi(arg + 8);
+		}
 		else if (strcmp(arg, "-h") == 0)
 		{
 			// Print usage
@@ -157,7 +163,8 @@ int main(int argc, char** argv)
 				 << "-no_sleep: Disable sleeping" << endl
 				 << "-rs: Record state" << endl
 				 << "-vs: Validate state" << endl
-				 << "-validate_hash=<hash>: Validate hash (return 0 if successful, 1 if failed)" << endl;
+				 << "-validate_hash=<hash>: Validate hash (return 0 if successful, 1 if failed)" << endl
+				 << "-repeat=<num>: Repeat all tests <num> times" << endl;
 			return 0;
 		}
 	}
@@ -198,200 +205,204 @@ int main(int argc, char** argv)
 	// Trace header
 	cout << "Motion Quality, Thread Count, Steps / Second, Hash" << endl;
 
-	// Iterate motion qualities
-	for (uint mq = 0; mq < 2; ++mq)
+	// Repeat test
+	for (int r = 0; r < repeat; ++r)
 	{
-		// Skip quality if another was specified
-		if (specified_quality != -1 && mq != (uint)specified_quality)
-			continue;
-
-		// Determine motion quality
-		EMotionQuality motion_quality = mq == 0? EMotionQuality::Discrete : EMotionQuality::LinearCast;
-		String motion_quality_str = mq == 0? "Discrete" : "LinearCast";
-
-		// Determine which thread counts to test
-		Array<uint> thread_permutations;
-		if (specified_threads > 0)
-			thread_permutations.push_back((uint)specified_threads - 1);
-		else
-			for (uint num_threads = 0; num_threads < thread::hardware_concurrency(); ++num_threads)
-				thread_permutations.push_back(num_threads);
-
-		// Test thread permutations
-		for (uint num_threads : thread_permutations)
+		// Iterate motion qualities
+		for (uint mq = 0; mq < 2; ++mq)
 		{
-			// Create job system with desired number of threads
-			JobSystemThreadPool job_system(cMaxPhysicsJobs, cMaxPhysicsBarriers, num_threads);
+			// Skip quality if another was specified
+			if (specified_quality != -1 && mq != (uint)specified_quality)
+				continue;
+
+			// Determine motion quality
+			EMotionQuality motion_quality = mq == 0? EMotionQuality::Discrete : EMotionQuality::LinearCast;
+			String motion_quality_str = mq == 0? "Discrete" : "LinearCast";
+
+			// Determine which thread counts to test
+			Array<uint> thread_permutations;
+			if (specified_threads > 0)
+				thread_permutations.push_back((uint)specified_threads - 1);
+			else
+				for (uint num_threads = 0; num_threads < thread::hardware_concurrency(); ++num_threads)
+					thread_permutations.push_back(num_threads);
 
-			// Create physics system
-			PhysicsSystem physics_system;
-			physics_system.Init(10240, 0, 65536, 10240, broad_phase_layer_interface, object_vs_broadphase_layer_filter, object_vs_object_layer_filter);
+			// Test thread permutations
+			for (uint num_threads : thread_permutations)
+			{
+				// Create job system with desired number of threads
+				JobSystemThreadPool job_system(cMaxPhysicsJobs, cMaxPhysicsBarriers, num_threads);
 
-			// Start test scene
-			scene->StartTest(physics_system, motion_quality);
+				// Create physics system
+				PhysicsSystem physics_system;
+				physics_system.Init(10240, 0, 65536, 10240, broad_phase_layer_interface, object_vs_broadphase_layer_filter, object_vs_object_layer_filter);
 
-			// Disable sleeping if requested
-			if (disable_sleep)
-			{
-				const BodyLockInterface &bli = physics_system.GetBodyLockInterfaceNoLock();
-				BodyIDVector body_ids;
-				physics_system.GetBodies(body_ids);
-				for (BodyID id : body_ids)
+				// Start test scene
+				scene->StartTest(physics_system, motion_quality);
+
+				// Disable sleeping if requested
+				if (disable_sleep)
 				{
-					BodyLockWrite lock(bli, id);
-					if (lock.Succeeded())
+					const BodyLockInterface &bli = physics_system.GetBodyLockInterfaceNoLock();
+					BodyIDVector body_ids;
+					physics_system.GetBodies(body_ids);
+					for (BodyID id : body_ids)
 					{
-						Body &body = lock.GetBody();
-						if (!body.IsStatic())
-							body.SetAllowSleeping(false);
+						BodyLockWrite lock(bli, id);
+						if (lock.Succeeded())
+						{
+							Body &body = lock.GetBody();
+							if (!body.IsStatic())
+								body.SetAllowSleeping(false);
+						}
 					}
 				}
-			}
 
-			// Optimize the broadphase to prevent an expensive first frame
-			physics_system.OptimizeBroadPhase();
+				// Optimize the broadphase to prevent an expensive first frame
+				physics_system.OptimizeBroadPhase();
 
-			// A tag used to identify the test
-			String tag = ToLower(motion_quality_str) + "_th" + ConvertToString(num_threads + 1);
+				// A tag used to identify the test
+				String tag = ToLower(motion_quality_str) + "_th" + ConvertToString(num_threads + 1);
 					     
-		#ifdef JPH_DEBUG_RENDERER
-			// Open renderer output
-			ofstream renderer_file;
-			if (enable_debug_renderer)
-				renderer_file.open(("performance_test_" + tag + ".jor").c_str(), ofstream::out | ofstream::binary | ofstream::trunc);
-			StreamOutWrapper renderer_stream(renderer_file);
-			DebugRendererRecorder renderer(renderer_stream);
-		#endif // JPH_DEBUG_RENDERER
-
-			// Open per frame timing output
-			ofstream per_frame_file;
-			if (enable_per_frame_recording)
-			{
-				per_frame_file.open(("per_frame_" + tag + ".csv").c_str(), ofstream::out | ofstream::trunc);
-				per_frame_file << "Frame, Time (ms)" << endl;
-			}
-
-			ofstream record_state_file;
-			ifstream validate_state_file;
-			if (record_state)
-				record_state_file.open(("state_" + ToLower(motion_quality_str) + ".bin").c_str(), ofstream::out | ofstream::binary | ofstream::trunc);
-			else if (validate_state)
-				validate_state_file.open(("state_" + ToLower(motion_quality_str) + ".bin").c_str(), ifstream::in | ifstream::binary);
-
-			chrono::nanoseconds total_duration(0);
-
-			// Step the world for a fixed amount of iterations
-			for (uint iterations = 0; iterations < max_iterations; ++iterations)
-			{
-				JPH_PROFILE_NEXTFRAME();
-				JPH_DET_LOG("Iteration: " << iterations);
-
-				// Start measuring
-				chrono::high_resolution_clock::time_point clock_start = chrono::high_resolution_clock::now();
-
-				// Do a physics step
-				physics_system.Update(cDeltaTime, 1, 1, &temp_allocator, &job_system);
-
-				// Stop measuring
-				chrono::high_resolution_clock::time_point clock_end = chrono::high_resolution_clock::now();
-				chrono::nanoseconds duration = chrono::duration_cast<chrono::nanoseconds>(clock_end - clock_start);
-				total_duration += duration;
-
 			#ifdef JPH_DEBUG_RENDERER
+				// Open renderer output
+				ofstream renderer_file;
 				if (enable_debug_renderer)
-				{
-					// Draw the state of the world
-					BodyManager::DrawSettings settings;
-					physics_system.DrawBodies(settings, &renderer);
-
-					// Mark end of frame
-					renderer.EndFrame();
-				}
+					renderer_file.open(("performance_test_" + tag + ".jor").c_str(), ofstream::out | ofstream::binary | ofstream::trunc);
+				StreamOutWrapper renderer_stream(renderer_file);
+				DebugRendererRecorder renderer(renderer_stream);
 			#endif // JPH_DEBUG_RENDERER
 
-				// Record time taken this iteration
+				// Open per frame timing output
+				ofstream per_frame_file;
 				if (enable_per_frame_recording)
-					per_frame_file << iterations << ", " << (1.0e-6 * duration.count()) << endl;
-
-				// Dump profile information every 100 iterations
-				if (enable_profiler && iterations % 100 == 0)
 				{
-					JPH_PROFILE_DUMP(tag + "_it" + ConvertToString(iterations));
+					per_frame_file.open(("per_frame_" + tag + ".csv").c_str(), ofstream::out | ofstream::trunc);
+					per_frame_file << "Frame, Time (ms)" << endl;
 				}
 
+				ofstream record_state_file;
+				ifstream validate_state_file;
 				if (record_state)
-				{
-					// Record state
-					StateRecorderImpl recorder;
-					physics_system.SaveState(recorder);
-
-					// Write to file
-					string data = recorder.GetData();
-					size_t size = data.size();
-					record_state_file.write((char *)&size, sizeof(size));
-					record_state_file.write(data.data(), size);
-				}
+					record_state_file.open(("state_" + ToLower(motion_quality_str) + ".bin").c_str(), ofstream::out | ofstream::binary | ofstream::trunc);
 				else if (validate_state)
+					validate_state_file.open(("state_" + ToLower(motion_quality_str) + ".bin").c_str(), ifstream::in | ifstream::binary);
+
+				chrono::nanoseconds total_duration(0);
+
+				// Step the world for a fixed amount of iterations
+				for (uint iterations = 0; iterations < max_iterations; ++iterations)
 				{
-					// Read state
-					size_t size = 0;
-					validate_state_file.read((char *)&size, sizeof(size));
-					string data;
-					data.resize(size);
-					validate_state_file.read(data.data(), size);
-
-					// Copy to validator
-					StateRecorderImpl validator;
-					validator.WriteBytes(data.data(), size);
-
-					// Validate state
-					validator.SetValidating(true);
-					physics_system.RestoreState(validator);
+					JPH_PROFILE_NEXTFRAME();
+					JPH_DET_LOG("Iteration: " << iterations);
+
+					// Start measuring
+					chrono::high_resolution_clock::time_point clock_start = chrono::high_resolution_clock::now();
+
+					// Do a physics step
+					physics_system.Update(cDeltaTime, 1, 1, &temp_allocator, &job_system);
+
+					// Stop measuring
+					chrono::high_resolution_clock::time_point clock_end = chrono::high_resolution_clock::now();
+					chrono::nanoseconds duration = chrono::duration_cast<chrono::nanoseconds>(clock_end - clock_start);
+					total_duration += duration;
+
+				#ifdef JPH_DEBUG_RENDERER
+					if (enable_debug_renderer)
+					{
+						// Draw the state of the world
+						BodyManager::DrawSettings settings;
+						physics_system.DrawBodies(settings, &renderer);
+
+						// Mark end of frame
+						renderer.EndFrame();
+					}
+				#endif // JPH_DEBUG_RENDERER
+
+					// Record time taken this iteration
+					if (enable_per_frame_recording)
+						per_frame_file << iterations << ", " << (1.0e-6 * duration.count()) << endl;
+
+					// Dump profile information every 100 iterations
+					if (enable_profiler && iterations % 100 == 0)
+					{
+						JPH_PROFILE_DUMP(tag + "_it" + ConvertToString(iterations));
+					}
+
+					if (record_state)
+					{
+						// Record state
+						StateRecorderImpl recorder;
+						physics_system.SaveState(recorder);
+
+						// Write to file
+						string data = recorder.GetData();
+						size_t size = data.size();
+						record_state_file.write((char *)&size, sizeof(size));
+						record_state_file.write(data.data(), size);
+					}
+					else if (validate_state)
+					{
+						// Read state
+						size_t size = 0;
+						validate_state_file.read((char *)&size, sizeof(size));
+						string data;
+						data.resize(size);
+						validate_state_file.read(data.data(), size);
+
+						// Copy to validator
+						StateRecorderImpl validator;
+						validator.WriteBytes(data.data(), size);
+
+						// Validate state
+						validator.SetValidating(true);
+						physics_system.RestoreState(validator);
+					}
+
+				#ifdef JPH_ENABLE_DETERMINISM_LOG
+					const BodyLockInterface &bli = physics_system.GetBodyLockInterfaceNoLock();
+					BodyIDVector body_ids;
+					physics_system.GetBodies(body_ids);
+					for (BodyID id : body_ids)
+					{
+						BodyLockRead lock(bli, id);
+						const Body &body = lock.GetBody();
+						if (!body.IsStatic())
+							JPH_DET_LOG(id << ": p: " << body.GetPosition() << " r: " << body.GetRotation() << " v: " << body.GetLinearVelocity() << " w: " << body.GetAngularVelocity());
+					}
+				#endif // JPH_ENABLE_DETERMINISM_LOG
 				}
 
-			#ifdef JPH_ENABLE_DETERMINISM_LOG
-				const BodyLockInterface &bli = physics_system.GetBodyLockInterfaceNoLock();
+				// Calculate hash of all positions and rotations of the bodies
+				uint64 hash = HashBytes(nullptr, 0); // Ensure we start with the proper seed
+				BodyInterface &bi = physics_system.GetBodyInterfaceNoLock();
 				BodyIDVector body_ids;
 				physics_system.GetBodies(body_ids);
 				for (BodyID id : body_ids)
 				{
-					BodyLockRead lock(bli, id);
-					const Body &body = lock.GetBody();
-					if (!body.IsStatic())
-						JPH_DET_LOG(id << ": p: " << body.GetPosition() << " r: " << body.GetRotation() << " v: " << body.GetLinearVelocity() << " w: " << body.GetAngularVelocity());
+					RVec3 pos = bi.GetPosition(id);
+					hash = HashBytes(&pos, 3 * sizeof(Real), hash);
+					Quat rot = bi.GetRotation(id);
+					hash = HashBytes(&rot, sizeof(Quat), hash);
 				}
-			#endif // JPH_ENABLE_DETERMINISM_LOG
-			}
 
-			// Calculate hash of all positions and rotations of the bodies
-			uint64 hash = HashBytes(nullptr, 0); // Ensure we start with the proper seed
-			BodyInterface &bi = physics_system.GetBodyInterfaceNoLock();
-			BodyIDVector body_ids;
-			physics_system.GetBodies(body_ids);
-			for (BodyID id : body_ids)
-			{
-				RVec3 pos = bi.GetPosition(id);
-				hash = HashBytes(&pos, 3 * sizeof(Real), hash);
-				Quat rot = bi.GetRotation(id);
-				hash = HashBytes(&rot, sizeof(Quat), hash);
-			}
+				// Convert hash to string
+				stringstream hash_stream;
+				hash_stream << "0x" << hex << hash << dec;
+				string hash_str = hash_stream.str();
 
-			// Convert hash to string
-			stringstream hash_stream;
-			hash_stream << "0x" << hex << hash << dec;
-			string hash_str = hash_stream.str();
+				// Stop test scene
+				scene->StopTest(physics_system);
 
-			// Stop test scene
-			scene->StopTest(physics_system);
+				// Trace stat line
+				cout << motion_quality_str << ", " << num_threads + 1 << ", " << double(max_iterations) / (1.0e-9 * total_duration.count()) << ", " << hash_str << endl;
 
-			// Trace stat line
-			cout << motion_quality_str << ", " << num_threads + 1 << ", " << double(max_iterations) / (1.0e-9 * total_duration.count()) << ", " << hash_str << endl;
-
-			// Check hash code
-			if (validate_hash != nullptr && hash_str != validate_hash)
-			{
-				cout << "Fail hash validation. Was: " << hash_str << ", expected: " << validate_hash << endl;
-				return 1;
+				// Check hash code
+				if (validate_hash != nullptr && hash_str != validate_hash)
+				{
+					cout << "Fail hash validation. Was: " << hash_str << ", expected: " << validate_hash << endl;
+					return 1;
+				}
 			}
 		}
 	}