mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 22:02:44 +00:00 
			
		
		
		
	Ladybird+LibWebView: Add -P/--enable-callgrind-profiling option
This adds a -P option to run Ladybird under callgrind. It starts with instrumentation disabled. To start capturing a profile (once Ladybird has launched) run `callgrind_control -i on` and to stop it again run `callgrind_control -i off`. P.s. This is pretty much stolen from Andreas (and is based on the patch everyone [that wants a profile] have been manually applying).
This commit is contained in:
		
							parent
							
								
									5db1eb9961
								
							
						
					
					
						commit
						0329ddf46a
					
				
					 12 changed files with 52 additions and 26 deletions
				
			
		|  | @ -27,9 +27,11 @@ | ||||||
| extern DeprecatedString s_serenity_resource_root; | extern DeprecatedString s_serenity_resource_root; | ||||||
| extern Browser::Settings* s_settings; | extern Browser::Settings* s_settings; | ||||||
| 
 | 
 | ||||||
| BrowserWindow::BrowserWindow(Browser::CookieJar& cookie_jar, StringView webdriver_content_ipc_path) | BrowserWindow::BrowserWindow(Browser::CookieJar& cookie_jar, StringView webdriver_content_ipc_path, WebView::EnableCallgrindProfiling enable_callgrind_profiling) | ||||||
|     : m_cookie_jar(cookie_jar) |     : m_cookie_jar(cookie_jar) | ||||||
|     , m_webdriver_content_ipc_path(webdriver_content_ipc_path) |     , m_webdriver_content_ipc_path(webdriver_content_ipc_path) | ||||||
|  |     , m_enable_callgrind_profiling(enable_callgrind_profiling) | ||||||
|  | 
 | ||||||
| { | { | ||||||
|     m_tabs_container = new QTabWidget(this); |     m_tabs_container = new QTabWidget(this); | ||||||
|     m_tabs_container->installEventFilter(this); |     m_tabs_container->installEventFilter(this); | ||||||
|  | @ -348,7 +350,7 @@ void BrowserWindow::debug_request(DeprecatedString const& request, DeprecatedStr | ||||||
| 
 | 
 | ||||||
| Tab& BrowserWindow::new_tab(QString const& url, Web::HTML::ActivateTab activate_tab) | Tab& BrowserWindow::new_tab(QString const& url, Web::HTML::ActivateTab activate_tab) | ||||||
| { | { | ||||||
|     auto tab = make<Tab>(this, m_webdriver_content_ipc_path); |     auto tab = make<Tab>(this, m_webdriver_content_ipc_path, m_enable_callgrind_profiling); | ||||||
|     auto tab_ptr = tab.ptr(); |     auto tab_ptr = tab.ptr(); | ||||||
|     m_tabs.append(std::move(tab)); |     m_tabs.append(std::move(tab)); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ class CookieJar; | ||||||
| class BrowserWindow : public QMainWindow { | class BrowserWindow : public QMainWindow { | ||||||
|     Q_OBJECT |     Q_OBJECT | ||||||
| public: | public: | ||||||
|     explicit BrowserWindow(Browser::CookieJar&, StringView webdriver_content_ipc_path); |     explicit BrowserWindow(Browser::CookieJar&, StringView webdriver_content_ipc_path, WebView::EnableCallgrindProfiling); | ||||||
| 
 | 
 | ||||||
|     WebContentView& view() const { return m_current_tab->view(); } |     WebContentView& view() const { return m_current_tab->view(); } | ||||||
| 
 | 
 | ||||||
|  | @ -70,4 +70,5 @@ private: | ||||||
|     Browser::CookieJar& m_cookie_jar; |     Browser::CookieJar& m_cookie_jar; | ||||||
| 
 | 
 | ||||||
|     StringView m_webdriver_content_ipc_path; |     StringView m_webdriver_content_ipc_path; | ||||||
|  |     WebView::EnableCallgrindProfiling m_enable_callgrind_profiling; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ | ||||||
| extern DeprecatedString s_serenity_resource_root; | extern DeprecatedString s_serenity_resource_root; | ||||||
| extern Browser::Settings* s_settings; | extern Browser::Settings* s_settings; | ||||||
| 
 | 
 | ||||||
| Tab::Tab(BrowserWindow* window, StringView webdriver_content_ipc_path) | Tab::Tab(BrowserWindow* window, StringView webdriver_content_ipc_path, WebView::EnableCallgrindProfiling enable_callgrind_profiling) | ||||||
|     : QWidget(window) |     : QWidget(window) | ||||||
|     , m_window(window) |     , m_window(window) | ||||||
| { | { | ||||||
|  | @ -28,7 +28,7 @@ Tab::Tab(BrowserWindow* window, StringView webdriver_content_ipc_path) | ||||||
|     m_layout->setSpacing(0); |     m_layout->setSpacing(0); | ||||||
|     m_layout->setContentsMargins(0, 0, 0, 0); |     m_layout->setContentsMargins(0, 0, 0, 0); | ||||||
| 
 | 
 | ||||||
|     m_view = new WebContentView(webdriver_content_ipc_path); |     m_view = new WebContentView(webdriver_content_ipc_path, enable_callgrind_profiling); | ||||||
|     m_toolbar = new QToolBar(this); |     m_toolbar = new QToolBar(this); | ||||||
|     m_location_edit = new LocationEdit(this); |     m_location_edit = new LocationEdit(this); | ||||||
|     m_reset_zoom_button = new QToolButton(m_toolbar); |     m_reset_zoom_button = new QToolButton(m_toolbar); | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ class BrowserWindow; | ||||||
| class Tab final : public QWidget { | class Tab final : public QWidget { | ||||||
|     Q_OBJECT |     Q_OBJECT | ||||||
| public: | public: | ||||||
|     Tab(BrowserWindow* window, StringView webdriver_content_ipc_path); |     Tab(BrowserWindow* window, StringView webdriver_content_ipc_path, WebView::EnableCallgrindProfiling); | ||||||
| 
 | 
 | ||||||
|     WebContentView& view() { return *m_view; } |     WebContentView& view() { return *m_view; } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -55,7 +55,7 @@ | ||||||
| #include <QTimer> | #include <QTimer> | ||||||
| #include <QToolTip> | #include <QToolTip> | ||||||
| 
 | 
 | ||||||
| WebContentView::WebContentView(StringView webdriver_content_ipc_path) | WebContentView::WebContentView(StringView webdriver_content_ipc_path, WebView::EnableCallgrindProfiling enable_callgrind_profiling) | ||||||
|     : m_webdriver_content_ipc_path(webdriver_content_ipc_path) |     : m_webdriver_content_ipc_path(webdriver_content_ipc_path) | ||||||
| { | { | ||||||
|     setMouseTracking(true); |     setMouseTracking(true); | ||||||
|  | @ -76,7 +76,7 @@ WebContentView::WebContentView(StringView webdriver_content_ipc_path) | ||||||
|         update_viewport_rect(); |         update_viewport_rect(); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     create_client(); |     create_client(enable_callgrind_profiling); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WebContentView::~WebContentView() | WebContentView::~WebContentView() | ||||||
|  | @ -599,12 +599,12 @@ void WebContentView::update_palette() | ||||||
|     client().async_update_system_theme(make_system_theme_from_qt_palette(*this)); |     client().async_update_system_theme(make_system_theme_from_qt_palette(*this)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WebContentView::create_client() | void WebContentView::create_client(WebView::EnableCallgrindProfiling enable_callgrind_profiling) | ||||||
| { | { | ||||||
|     m_client_state = {}; |     m_client_state = {}; | ||||||
| 
 | 
 | ||||||
|     auto candidate_web_content_paths = get_paths_for_helper_process("WebContent"sv).release_value_but_fixme_should_propagate_errors(); |     auto candidate_web_content_paths = get_paths_for_helper_process("WebContent"sv).release_value_but_fixme_should_propagate_errors(); | ||||||
|     auto new_client = launch_web_content_process(candidate_web_content_paths).release_value_but_fixme_should_propagate_errors(); |     auto new_client = launch_web_content_process(candidate_web_content_paths, enable_callgrind_profiling).release_value_but_fixme_should_propagate_errors(); | ||||||
| 
 | 
 | ||||||
|     m_web_content_notifier.setSocket(new_client->socket().fd().value()); |     m_web_content_notifier.setSocket(new_client->socket().fd().value()); | ||||||
|     m_web_content_notifier.setEnabled(true); |     m_web_content_notifier.setEnabled(true); | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ class WebContentView final | ||||||
|     , public WebView::ViewImplementation { |     , public WebView::ViewImplementation { | ||||||
|     Q_OBJECT |     Q_OBJECT | ||||||
| public: | public: | ||||||
|     explicit WebContentView(StringView webdriver_content_ipc_path); |     explicit WebContentView(StringView webdriver_content_ipc_path, WebView::EnableCallgrindProfiling); | ||||||
|     virtual ~WebContentView() override; |     virtual ~WebContentView() override; | ||||||
| 
 | 
 | ||||||
|     Function<String(Web::HTML::ActivateTab)> on_new_tab; |     Function<String(Web::HTML::ActivateTab)> on_new_tab; | ||||||
|  | @ -185,7 +185,7 @@ signals: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     // ^WebView::ViewImplementation
 |     // ^WebView::ViewImplementation
 | ||||||
|     virtual void create_client() override; |     virtual void create_client(WebView::EnableCallgrindProfiling = WebView::EnableCallgrindProfiling::No) override; | ||||||
|     virtual void update_zoom() override; |     virtual void update_zoom() override; | ||||||
| 
 | 
 | ||||||
|     void request_repaint(); |     void request_repaint(); | ||||||
|  |  | ||||||
|  | @ -67,11 +67,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) | ||||||
| 
 | 
 | ||||||
|     StringView raw_url; |     StringView raw_url; | ||||||
|     StringView webdriver_content_ipc_path; |     StringView webdriver_content_ipc_path; | ||||||
|  |     bool enable_callgrind_profiling = false; | ||||||
| 
 | 
 | ||||||
|     Core::ArgsParser args_parser; |     Core::ArgsParser args_parser; | ||||||
|     args_parser.set_general_help("The Ladybird web browser :^)"); |     args_parser.set_general_help("The Ladybird web browser :^)"); | ||||||
|     args_parser.add_positional_argument(raw_url, "URL to open", "url", Core::ArgsParser::Required::No); |     args_parser.add_positional_argument(raw_url, "URL to open", "url", Core::ArgsParser::Required::No); | ||||||
|     args_parser.add_option(webdriver_content_ipc_path, "Path to WebDriver IPC for WebContent", "webdriver-content-path", 0, "path"); |     args_parser.add_option(webdriver_content_ipc_path, "Path to WebDriver IPC for WebContent", "webdriver-content-path", 0, "path"); | ||||||
|  |     args_parser.add_option(enable_callgrind_profiling, "Enable Callgrind profiling", "enable-callgrind-profiling", 'P'); | ||||||
|     args_parser.parse(arguments); |     args_parser.parse(arguments); | ||||||
| 
 | 
 | ||||||
|     auto get_formatted_url = [&](StringView const& raw_url) -> ErrorOr<URL> { |     auto get_formatted_url = [&](StringView const& raw_url) -> ErrorOr<URL> { | ||||||
|  | @ -90,7 +92,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) | ||||||
|     auto cookie_jar = TRY(Browser::CookieJar::create(*database)); |     auto cookie_jar = TRY(Browser::CookieJar::create(*database)); | ||||||
| 
 | 
 | ||||||
|     s_settings = adopt_own_if_nonnull(new Browser::Settings()); |     s_settings = adopt_own_if_nonnull(new Browser::Settings()); | ||||||
|     BrowserWindow window(cookie_jar, webdriver_content_ipc_path); |     BrowserWindow window(cookie_jar, webdriver_content_ipc_path, enable_callgrind_profiling ? WebView::EnableCallgrindProfiling::Yes : WebView::EnableCallgrindProfiling::No); | ||||||
|     window.setWindowTitle("Ladybird"); |     window.setWindowTitle("Ladybird"); | ||||||
|     window.resize(800, 600); |     window.resize(800, 600); | ||||||
|     window.show(); |     window.show(); | ||||||
|  |  | ||||||
|  | @ -59,7 +59,7 @@ void OutOfProcessWebView::handle_web_content_process_crash() | ||||||
|     load_html(builder.to_deprecated_string(), m_url); |     load_html(builder.to_deprecated_string(), m_url); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void OutOfProcessWebView::create_client() | void OutOfProcessWebView::create_client(EnableCallgrindProfiling) | ||||||
| { | { | ||||||
|     m_client_state = {}; |     m_client_state = {}; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -121,7 +121,7 @@ private: | ||||||
|     virtual void did_scroll() override; |     virtual void did_scroll() override; | ||||||
| 
 | 
 | ||||||
|     // ^WebView::ViewImplementation
 |     // ^WebView::ViewImplementation
 | ||||||
|     virtual void create_client() override; |     virtual void create_client(EnableCallgrindProfiling = EnableCallgrindProfiling::No) override; | ||||||
|     virtual void update_zoom() override; |     virtual void update_zoom() override; | ||||||
|     virtual void notify_server_did_layout(Badge<WebContentClient>, Gfx::IntSize content_size) override; |     virtual void notify_server_did_layout(Badge<WebContentClient>, Gfx::IntSize content_size) override; | ||||||
|     virtual void notify_server_did_paint(Badge<WebContentClient>, i32 bitmap_id) override; |     virtual void notify_server_did_paint(Badge<WebContentClient>, i32 bitmap_id) override; | ||||||
|  |  | ||||||
|  | @ -126,7 +126,7 @@ void ViewImplementation::run_javascript(StringView js_source) | ||||||
| 
 | 
 | ||||||
| #if !defined(AK_OS_SERENITY) | #if !defined(AK_OS_SERENITY) | ||||||
| 
 | 
 | ||||||
| ErrorOr<NonnullRefPtr<WebView::WebContentClient>> ViewImplementation::launch_web_content_process(ReadonlySpan<String> candidate_web_content_paths) | ErrorOr<NonnullRefPtr<WebView::WebContentClient>> ViewImplementation::launch_web_content_process(ReadonlySpan<String> candidate_web_content_paths, EnableCallgrindProfiling enable_callgrind_profiling) | ||||||
| { | { | ||||||
|     int socket_fds[2] {}; |     int socket_fds[2] {}; | ||||||
|     TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); |     TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); | ||||||
|  | @ -149,15 +149,22 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> ViewImplementation::launch_web | ||||||
| 
 | 
 | ||||||
|         auto webcontent_fd_passing_socket_string = TRY(String::number(wc_fd_passing_fd)); |         auto webcontent_fd_passing_socket_string = TRY(String::number(wc_fd_passing_fd)); | ||||||
| 
 | 
 | ||||||
|         auto arguments = Array { |  | ||||||
|             "WebContent"sv, |  | ||||||
|             "--webcontent-fd-passing-socket"sv, |  | ||||||
|             webcontent_fd_passing_socket_string |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         ErrorOr<void> result; |         ErrorOr<void> result; | ||||||
|         for (auto const& path : candidate_web_content_paths) { |         for (auto const& path : candidate_web_content_paths) { | ||||||
|             result = Core::System::exec(path, arguments, Core::System::SearchInPath::Yes); |             constexpr auto callgrind_prefix_length = 3; | ||||||
|  |             auto arguments_with_callgrind_prefix = Array { | ||||||
|  |                 "valgrind"sv, | ||||||
|  |                 "--tool=callgrind"sv, | ||||||
|  |                 "--instr-atstart=no"sv, | ||||||
|  |                 path.bytes_as_string_view(), | ||||||
|  |                 "--webcontent-fd-passing-socket"sv, | ||||||
|  |                 webcontent_fd_passing_socket_string | ||||||
|  |             }; | ||||||
|  |             auto arguments = arguments_with_callgrind_prefix.span(); | ||||||
|  |             if (enable_callgrind_profiling == EnableCallgrindProfiling::No) | ||||||
|  |                 arguments = arguments.slice(callgrind_prefix_length); | ||||||
|  | 
 | ||||||
|  |             result = Core::System::exec(arguments[0], arguments, Core::System::SearchInPath::Yes); | ||||||
|             if (!result.is_error()) |             if (!result.is_error()) | ||||||
|                 break; |                 break; | ||||||
|         } |         } | ||||||
|  | @ -176,6 +183,13 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> ViewImplementation::launch_web | ||||||
|     auto new_client = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) WebView::WebContentClient(move(socket), *this))); |     auto new_client = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) WebView::WebContentClient(move(socket), *this))); | ||||||
|     new_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(ui_fd_passing_fd))); |     new_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(ui_fd_passing_fd))); | ||||||
| 
 | 
 | ||||||
|  |     if (enable_callgrind_profiling == EnableCallgrindProfiling::Yes) { | ||||||
|  |         dbgln(); | ||||||
|  |         dbgln("\033[1;45mLaunched WebContent process under callgrind!\033[0m"); | ||||||
|  |         dbgln("\033[100mRun `\033[4mcallgrind_control -i on\033[24m` to start instrumentation and `\033[4mcallgrind_control -i off\033[24m` stop it again.\033[0m"); | ||||||
|  |         dbgln(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     return new_client; |     return new_client; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -18,6 +18,12 @@ | ||||||
| 
 | 
 | ||||||
| namespace WebView { | namespace WebView { | ||||||
| 
 | 
 | ||||||
|  | // Note: This only exists inside Serenity to avoid #ifdefs in all implementors of ViewImplementation.
 | ||||||
|  | enum class EnableCallgrindProfiling { | ||||||
|  |     No, | ||||||
|  |     Yes | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| class ViewImplementation { | class ViewImplementation { | ||||||
| public: | public: | ||||||
|     virtual ~ViewImplementation() { } |     virtual ~ViewImplementation() { } | ||||||
|  | @ -120,11 +126,12 @@ protected: | ||||||
| 
 | 
 | ||||||
|     WebContentClient& client(); |     WebContentClient& client(); | ||||||
|     WebContentClient const& client() const; |     WebContentClient const& client() const; | ||||||
|     virtual void create_client() = 0; |  | ||||||
|     virtual void update_zoom() = 0; |     virtual void update_zoom() = 0; | ||||||
| 
 | 
 | ||||||
|  |     virtual void create_client(EnableCallgrindProfiling = EnableCallgrindProfiling::No) {}; | ||||||
|  | 
 | ||||||
| #if !defined(AK_OS_SERENITY) | #if !defined(AK_OS_SERENITY) | ||||||
|     ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(ReadonlySpan<String> candidate_web_content_paths); |     ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(ReadonlySpan<String> candidate_web_content_paths, EnableCallgrindProfiling = EnableCallgrindProfiling::No); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     struct SharedBitmap { |     struct SharedBitmap { | ||||||
|  |  | ||||||
|  | @ -157,7 +157,7 @@ private: | ||||||
| 
 | 
 | ||||||
|     void notify_server_did_finish_handling_input_event(bool) override { } |     void notify_server_did_finish_handling_input_event(bool) override { } | ||||||
|     void update_zoom() override { } |     void update_zoom() override { } | ||||||
|     void create_client() override { } |     void create_client(WebView::EnableCallgrindProfiling) override { } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static ErrorOr<NonnullRefPtr<Core::Timer>> load_page_for_screenshot_and_exit(Core::EventLoop& event_loop, HeadlessWebContentView& view, int screenshot_timeout) | static ErrorOr<NonnullRefPtr<Core::Timer>> load_page_for_screenshot_and_exit(Core::EventLoop& event_loop, HeadlessWebContentView& view, int screenshot_timeout) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 MacDue
						MacDue