Repository: godotengine/godot
File: main/main.cpp (C++)

Code before:
		frames = 0;
	}

	iterating--;

	if (movie_writer) {
		GodotProfileZoneGrouped(_profile_zone, "movie_writer->add_frame");
		movie_writer->add_frame();
	}

#ifdef TOOLS_ENABLED
	bool quit_after_timeout = false;
#endif
	if ((quit_after > 0) && (Engine::get_singleton()->_process_frames >= quit_after)) {
#ifdef TOOLS_ENABLED
		quit_after_timeout = true;
#endif
		exit = true;
	}

#ifdef TOOLS_ENABLED
	if (wait_for_import && EditorFileSystem::get_singleton() && EditorFileSystem::get_singleton()->doing_first_scan()) {
		exit = false;
	}
#endif

	if (fixed_fps != -1) {
		return exit;
	}

	SceneTree *scene_tree = SceneTree::get_singleton();
	bool wake_for_events = scene_tree && scene_tree->is_accessibility_enabled();

	GodotProfileZoneGrouped(_profile_zone, "OS::add_frame_delay");
	OS::get_singleton()->add_frame_delay(DisplayServer::get_singleton()->window_can_draw(), wake_for_events);

#ifdef TOOLS_ENABLED
	if (auto_build_solutions) {
		auto_build_solutions = false;
		// Only relevant when running the editor.
		if (!editor) {
			OS::get_singleton()->set_exit_code(EXIT_FAILURE);
			ERR_FAIL_V_MSG(true,
					"Command line option --build-solutions was passed, but no project is being edited. Aborting.");
		}
		if (!EditorNode::get_singleton()->call_build()) {
			OS::get_singleton()->set_exit_code(EXIT_FAILURE);
			ERR_FAIL_V_MSG(true,
					"Command line option --build-solutions was passed, but the build callback failed. Aborting.");
		}
	}

Review comment (performance):
With the perfetto macros, this is going to end this group step at the end of the if statement scope, which looks like a mistake in the resulting trace (there will be a gap in the trace which seems to defeat the purpose of the Grouped API). You probably want a regular event here:

GodotProfileZone("movie_writer->add_frame");

With the tracy macros, this kinda works because of the placement new taking over the existing object's scope, but it's also kind of an anti-pattern for a trace macro's scope to continue beyond the code scope -- ie this "add_frame" event will actually include a bunch of code after this if statement's scope ends, so that could cause some confusion when trying to reason about the cost of this codepath. "add_frame" might look really expensive even though it was actually some slow code on lines 4860-4881.

Maybe a good rule for this GodotProfileZoneGrouped API is to only use it in a single scope? And for any child scopes just use an additional GodotProfileZone().

Code after:
				if (print_fps) {
					print_line(vformat("Editor FPS: %d (%s mspf)", frames, rtos(1000.0 / frames).pad_decimals(2)));
				}
			} else if (print_fps || GLOBAL_GET("debug/settings/stdout/print_fps")) {
				print_line(vformat("Project FPS: %d (%s mspf)", frames, rtos(1000.0 / frames).pad_decimals(2)));
			}
		} else {
			hide_print_fps_attempts--;
		}

		Engine::get_singleton()->_fps = frames;
		performance->set_process_time(USEC_TO_SEC(process_max));
		performance->set_physics_process_time(USEC_TO_SEC(physics_process_max));
		performance->set_navigation_process_time(USEC_TO_SEC(navigation_process_max));
		process_max = 0;
		physics_process_max = 0;
		navigation_process_max = 0;

		frame %= 1000000;
		frames = 0;
	}

	iterating--;

	if (movie_writer) {
		GodotProfileZoneGrouped(_profile_zone, "movie_writer->add_frame");
		movie_writer->add_frame();
	}

#ifdef TOOLS_ENABLED
	bool quit_after_timeout = false;
#endif
	if ((quit_after > 0) && (Engine::get_singleton()->_process_frames >= quit_after)) {
#ifdef TOOLS_ENABLED
		quit_after_timeout = true;
#endif
		exit = true;
	}

#ifdef TOOLS_ENABLED
	if (wait_for_import && EditorFileSystem::get_singleton() && EditorFileSystem::get_singleton()->doing_first_scan()) {
		exit = false;
	}
#endif

	if (fixed_fps != -1) {
		return exit;
	}

	SceneTree *scene_tree = SceneTree::get_singleton();
	bool wake_for_events = scene_tree && scene_tree->is_accessibility_enabled();