diff --git a/locales/de/app.ftl b/locales/de/app.ftl index aa2627d921..20a129a465 100644 --- a/locales/de/app.ftl +++ b/locales/de/app.ftl @@ -319,6 +319,15 @@ Home--load-files-from-other-tools2 = Linux perf, Android SimplePerf, die Chrome Performance Panel, Android Studio oder eine Datei im dhat-Format oder Googles Trace-Event-Format. Erfahren Sie, wie Sie Ihren eigenen Importeur schreiben. +Home--install-chrome-extension = Installieren Sie die Chrome-Erweiterung +Home--chrome-extension-instructions = + Verwenden Sie die { -profiler-brand-name }-Erweiterung für Chrome, + um Leistungsprofile in Chrome zu erfassen und im { -profiler-brand-name } + zu analysieren. Installieren Sie die Erweiterung aus dem Chrome Web Store. +Home--chrome-extension-recording-instructions = + Verwenden Sie nach der Installation das Symbolleisten-Symbol der Erweiterung + oder die Tastenkombinationen zum Starten und Stoppen der Profilerstellung. Sie können auch + Profile exportieren und hier zur detaillierten Analyse laden. ## IdleSearchField ## The component that is used for all the search inputs in the application. diff --git a/locales/en-GB/app.ftl b/locales/en-GB/app.ftl index 1019e75e4f..c403007b0f 100644 --- a/locales/en-GB/app.ftl +++ b/locales/en-GB/app.ftl @@ -343,6 +343,15 @@ Home--load-files-from-other-tools2 = any file using the dhat format or Google’s Trace Event Format. Learn how to write your own importer. +Home--install-chrome-extension = Install the Chrome extension +Home--chrome-extension-instructions = + Use the { -profiler-brand-name } extension for Chrome + to capture performance profiles in Chrome and analyse them in the + { -profiler-brand-name }. Install the extension from the Chrome Web Store. +Home--chrome-extension-recording-instructions = + Once installed, use the extension’s + toolbar icon or the shortcuts to start and stop profiling. You can also + export profiles and load them here for detailed analysis. ## IdleSearchField ## The component that is used for all the search inputs in the application. diff --git a/locales/en-US/app.ftl b/locales/en-US/app.ftl index a078f4a5a2..8a1d03794b 100644 --- a/locales/en-US/app.ftl +++ b/locales/en-US/app.ftl @@ -365,6 +365,14 @@ Home--load-files-from-other-tools2 = Format. Learn how to write your own importer. +Home--install-chrome-extension = Install the Chrome extension +Home--chrome-extension-instructions = Use the { -profiler-brand-name } extension for Chrome + to capture performance profiles in Chrome and analyze them in the + { -profiler-brand-name }. Install the extension from the Chrome Web Store. +Home--chrome-extension-recording-instructions = Once installed, use the extension’s + toolbar icon or the shortcuts to start and stop profiling. You can also + export profiles and load them here for detailed analysis. + ## IdleSearchField ## The component that is used for all the search inputs in the application. diff --git a/locales/fr/app.ftl b/locales/fr/app.ftl index c2721701c9..17e4e22e24 100644 --- a/locales/fr/app.ftl +++ b/locales/fr/app.ftl @@ -30,6 +30,7 @@ AppHeader--github-icon = ## AppViewRouter ## This is used for displaying errors when loading the application. +AppViewRouter--error-from-post-message = Impossible d’importer le profil. AppViewRouter--error-unpublished = Impossible de récupérer le profil depuis { -firefox-brand-name }. AppViewRouter--error-from-file = Impossible de lire le fichier ou d’analyser le profil qu’il contient. AppViewRouter--error-local = Pas encore implémenté. @@ -142,6 +143,30 @@ CallTreeSidebar--call-node-details = Détails du nœud d’appel ## in the functions it called. "Running time" is the time spent in the function ## itself, including the time spent in the functions it called. +CallTreeSidebar--traced-running-time = + .label = Temps d’exécution tracé +CallTreeSidebar--traced-self-time = + .label = Temps individuel tracé +CallTreeSidebar--running-time = + .label = Temps d’exécution +CallTreeSidebar--self-time = + .label = Temps individuel +CallTreeSidebar--running-samples = + .label = Échantillons totaux +CallTreeSidebar--self-samples = + .label = Échantillons individuels +CallTreeSidebar--running-size = + .label = Taille totale +CallTreeSidebar--self-size = + .label = Taille individuelle +CallTreeSidebar--categories = Catégories +CallTreeSidebar--implementation = Implémentation +CallTreeSidebar--running-milliseconds = Millisecondes totales +CallTreeSidebar--running-sample-count = Nombre d’échantillons total +CallTreeSidebar--running-bytes = Octets totaux +CallTreeSidebar--self-milliseconds = Millisecondes individuelles +CallTreeSidebar--self-sample-count = Nombre d’échantillons individuels +CallTreeSidebar--self-bytes = Octets individuels ## CompareHome ## This is used in the page to compare two profiles. @@ -577,6 +602,7 @@ ProfileFilterNavigator--full-range-with-duration = Plage entière ({ $fullRangeD ## Profile Loader Animation +ProfileLoaderAnimation--loading-from-post-message = Importation et traitement du profil… ProfileLoaderAnimation--loading-unpublished = Importation du profil directement depuis { -firefox-brand-name }… ProfileLoaderAnimation--loading-from-file = Lecture du fichier et traitement du profil… ProfileLoaderAnimation--loading-local = Pas encore implémenté. @@ -655,6 +681,7 @@ TabBar--js-tracer-tab = Traceur JS ## range at the top left corner for profiler analysis view. It's used to switch ## between tabs that were captured in the profile. +TabSelectorMenu--all-tabs-and-windows = Tous les onglets et fenêtres ## TrackContextMenu ## This is used as a context menu for timeline to organize the tracks in the @@ -672,6 +699,10 @@ TrackContextMenu--hide-other-screenshots-tracks = Masquer les autres pistes de c TrackContextMenu--hide-track = Masquer « { $trackName } » TrackContextMenu--show-all-tracks = Afficher toutes les pistes TrackContextMenu--show-local-tracks-in-process = Afficher toutes les pistes de ce processus +# This is used as the context menu item to hide all tracks of the selected track's type. +# Variables: +# $type (String) - Name of the type of selected track to hide. +TrackContextMenu--hide-all-tracks-by-selected-track-type = Masquer les pistes de type « { $type } » # This is used in the tracks context menu as a button to show all the tracks # that match the search filter. TrackContextMenu--show-all-matching-tracks = Afficher toutes les pistes correspondantes @@ -724,6 +755,21 @@ TrackPower--tooltip-power-watt = { $value } W # $value (String) - the power value at this location TrackPower--tooltip-power-milliwatt = { $value } mW .label = Puissance +# This is used in the tooltip when the power value uses the kilowatt unit. +# Variables: +# $value (String) - the power value at this location +TrackPower--tooltip-average-power-kilowatt = { $value } kW + .label = Puissance moyenne pour la sélection actuelle +# This is used in the tooltip when the power value uses the watt unit. +# Variables: +# $value (String) - the power value at this location +TrackPower--tooltip-average-power-watt = { $value } W + .label = Puissance moyenne pour la sélection actuelle +# This is used in the tooltip when the instant power value uses the milliwatt unit. +# Variables: +# $value (String) - the power value at this location +TrackPower--tooltip-average-power-milliwatt = { $value } mW + .label = Puissance moyenne pour la sélection actuelle # This is used in the tooltip when the energy used in the current range uses the # kilowatt-hour unit. # Variables: diff --git a/locales/fy-NL/app.ftl b/locales/fy-NL/app.ftl index c0a8642c21..406c8af87d 100644 --- a/locales/fy-NL/app.ftl +++ b/locales/fy-NL/app.ftl @@ -343,6 +343,15 @@ Home--load-files-from-other-tools2 = elk bestân mei it dhat-formaat of de Trace Event-yndieling fan Google brûkt. Lês hoe’t jo jo eigen ymportearder skriuwe. +Home--install-chrome-extension = De Chrome-útwreiding ynstallearje +Home--chrome-extension-instructions = + Brûk de { -profiler-brand-name }-útwreiding foar Chrome + om prestaasjeprofilen yn Chrome fêst te lizzen en se yn de + { -profiler-brand-name } te analysearjen. Ynstallearje de útwreiding fan de Chrome Web Store út. +Home--chrome-extension-recording-instructions = + Brûk nei ynstallaasje it arkbalkepiktogram fan de + útwreiding of de fluchkeppelingen om it profilearjen te starten en te stopjen. Jo kinne ek + profilen eksportearje en dizze hjir lade foar detaillearre analyze. ## IdleSearchField ## The component that is used for all the search inputs in the application. diff --git a/locales/it/app.ftl b/locales/it/app.ftl index c03dee61fb..7d6315cb24 100644 --- a/locales/it/app.ftl +++ b/locales/it/app.ftl @@ -261,6 +261,9 @@ Home--your-recent-uploaded-recordings-title = Le tue registrazioni caricate di r Home--load-files-from-other-tools2 = { -profiler-brand-name } può anche importare profili da altri profiler, come Linux perf, Android SimplePerf, il pannello prestazioni di Chrome, Android Studio o qualsiasi file che utilizzi il formato dhat o Trace Event di Google. Scopri come creare uno strumento di importazione. +Home--install-chrome-extension = Installa l’estensione per Chrome +Home--chrome-extension-instructions = Utilizza l’estensione { -profiler-brand-name } per Chrome per acquisire i profili delle prestazioni in Chrome e analizzarli in { -profiler-brand-name }. Installa l’estensione dal Chrome Web Store. +Home--chrome-extension-recording-instructions = Una volta installata, utilizza l’icona dell’estensione nella barra degli strumenti o le scorciatoie per avviare e interrompere la profilazione. Puoi anche esportare i profili e caricarli qui per un’analisi dettagliata. ## IdleSearchField ## The component that is used for all the search inputs in the application. diff --git a/locales/nl/app.ftl b/locales/nl/app.ftl index ce73c92eb0..0440d44fe8 100644 --- a/locales/nl/app.ftl +++ b/locales/nl/app.ftl @@ -343,6 +343,15 @@ Home--load-files-from-other-tools2 = elk bestand dat de dhat-indeling of de Trace Event-indeling van Google gebruikt. Ontdek hoe u uw eigen importroutine schrijft. +Home--install-chrome-extension = De Chrome-extensie installeren +Home--chrome-extension-instructions = + Gebruik de { -profiler-brand-name }-extensie voor Chrome + om prestatieprofielen in Chrome vast te leggen en ze in de + { -profiler-brand-name } te analyseren. Installeer de extensie vanuit de Chrome Web Store. +Home--chrome-extension-recording-instructions = + Gebruik na installatie het werkbalkpictogram van de + extensie of de snelkoppelingen om het profileren te starten en te stoppen. U kunt ook + profielen exporteren en deze hier laden voor gedetailleerde analyse. ## IdleSearchField ## The component that is used for all the search inputs in the application. diff --git a/locales/pt-BR/app.ftl b/locales/pt-BR/app.ftl index af0b82b3da..1f8615cdbb 100644 --- a/locales/pt-BR/app.ftl +++ b/locales/pt-BR/app.ftl @@ -272,6 +272,9 @@ Home--your-recent-uploaded-recordings-title = Suas gravações enviadas recentem # We replace the elements such as and with links to the # documentation to use these tools. Home--load-files-from-other-tools2 = O { -profiler-brand-name } também pode importar profiles de outros criadores de profile, como o Linux perf, o Android SimplePerf, o painel de desempenho do Chrome, o Android Studio, ou qualquer arquivo nos formatos dhat ou Trace Event do Google. Saiba como criar seu próprio importador. +Home--install-chrome-extension = Instale a extensão para Chrome +Home--chrome-extension-instructions = Use a extensão { -profiler-brand-name } para Chrome para capturar profiles de desempenho no Chrome e analisar no { -profiler-brand-name }. Instale a extensão a partir do Chrome Web Store. +Home--chrome-extension-recording-instructions = Após instalar, use o ícone da extensão na barra de ferramentas ou os atalhos para iniciar e encerrar a gravação de profiles. Você também pode exportar profiles e carregar aqui para análises detalhadas. ## IdleSearchField ## The component that is used for all the search inputs in the application. diff --git a/locales/ru/app.ftl b/locales/ru/app.ftl index 31936cca0f..6a21e816bc 100644 --- a/locales/ru/app.ftl +++ b/locales/ru/app.ftl @@ -340,6 +340,15 @@ Home--load-files-from-other-tools2 = панель производительности Chrome, Android Studio или любой файл, использующий формат dhat или Формат отслеживания событий Google. Узнайте, как написать собственный инструмент импорта. +Home--install-chrome-extension = Установите расширение Chrome +Home--chrome-extension-instructions = + Используйте расширение { -profiler-brand-name } для Chrome + для сбора профилей производительности в Chrome и анализа их в + { -profiler-brand-name }. Установите расширение из интернет-магазина Chrome. +Home--chrome-extension-recording-instructions = + После установки используйте значок + расширения на панели инструментов или сочетания клавиш для запуска и остановки профилирования. Вы также можете + экспортировать профили и загрузить их здесь для подробного анализа. ## IdleSearchField ## The component that is used for all the search inputs in the application. diff --git a/locales/uk/app.ftl b/locales/uk/app.ftl index b8e1a62e35..5f1bee379d 100644 --- a/locales/uk/app.ftl +++ b/locales/uk/app.ftl @@ -30,6 +30,7 @@ AppHeader--github-icon = ## AppViewRouter ## This is used for displaying errors when loading the application. +AppViewRouter--error-from-post-message = Не вдалося імпортувати профіль. AppViewRouter--error-unpublished = Не вдалося відновити профіль із { -firefox-brand-name }. AppViewRouter--error-from-file = Не вдалося прочитати файл або проаналізувати профіль у ньому. AppViewRouter--error-local = Ще не впроваджено. @@ -676,6 +677,7 @@ ProfileFilterNavigator--full-range-with-duration = Повний діапазон ## Profile Loader Animation +ProfileLoaderAnimation--loading-from-post-message = Імпорт та обробка профілю… ProfileLoaderAnimation--loading-unpublished = Імпортування профілю безпосередньо з { -firefox-brand-name }… ProfileLoaderAnimation--loading-from-file = Читання файлу та обробка профілю… ProfileLoaderAnimation--loading-local = Ще не впроваджено. diff --git a/locales/zh-CN/app.ftl b/locales/zh-CN/app.ftl index 8a3273c56e..f1de57521b 100644 --- a/locales/zh-CN/app.ftl +++ b/locales/zh-CN/app.ftl @@ -262,6 +262,9 @@ Home--your-recent-uploaded-recordings-title = 您最近上传的记录 # We replace the elements such as and with links to the # documentation to use these tools. Home--load-files-from-other-tools2 = { -profiler-brand-name } 也可以从其他分析器导入记录,例如 Linux perfAndroid SimplePerf、Chrome 性能面板、Android Studio,支持直接导入 dhatGoogle 的 Trace Event 格式保存的分析记录。点此了解如何编写您自己的导入程序。 +Home--install-chrome-extension = 安装 Chrome 扩展 +Home--chrome-extension-instructions = 使用 Chrome 版 { -profiler-brand-name } 扩展,在 Chrome 中捕获性能分析记录,并通过 { -profiler-brand-name } 分析。可到 Chrome 应用商店安装扩展。 +Home--chrome-extension-recording-instructions = 安装后,即可使用扩展的工具栏图标和快捷键来开始或停止分析,也可以导出分析记录并在此处加载以进行详细分析。 ## IdleSearchField ## The component that is used for all the search inputs in the application. diff --git a/locales/zh-TW/app.ftl b/locales/zh-TW/app.ftl index 17f24e0b3e..efb7a37f3a 100644 --- a/locales/zh-TW/app.ftl +++ b/locales/zh-TW/app.ftl @@ -174,8 +174,8 @@ CallTreeSidebar--self-bytes = Self 位元組 CompareHome--instruction-title = 輸入您想要用來比較的檢測檔網址 CompareHome--instruction-content = 此工具將從每個效能檢測檔當中抽出選擇的軌道與範圍相關資料,並將它們放到相同的畫面上,方便比較。 -CompareHome--form-label-profile1 = 檢測檔 1: -CompareHome--form-label-profile2 = 檢測檔 2: +CompareHome--form-label-profile1 = 檢測檔 1: +CompareHome--form-label-profile2 = 檢測檔 2: CompareHome--submit-button = .value = 取得檢測檔 @@ -249,11 +249,11 @@ Home--enable-button-unavailable = Home--web-channel-unavailable = 此檢測器無法連線到 WebChannel。通常是因為執行檢測器的主機與 devtools.performance.recording.ui-base-url 偏好設定當中指定的主機不同。若您想要使用此檢測器捕捉新的效能檢測檔,並可程式化控制檢測器選單按鈕,可到 about:config 調整該偏好設定。 Home--record-instructions = 請點擊檢測按鈕或按下鍵盤快速鍵即可開始進行檢測。進行效能紀錄時,此圖示將會顯示成藍色。按下捕捉即可將資料載入到 profiler.firefox.com。 Home--instructions-content = 需要使用 { -firefox-brand-name } 紀錄效能檢測檔。但可以使用任何現代瀏覽器檢視現有的檢測檔。 -Home--record-instructions-start-stop = 停止並開始檢測 +Home--record-instructions-start-stop = 停止或開始檢測 Home--record-instructions-capture-load = 捕捉並載入檢測檔 Home--profiler-motto = 捕捉效能檢測檔。分析、分享、讓網站運作更快。 Home--additional-content-title = 載入現有檢測檔 -Home--additional-content-content = 您可以將效能檢測檔拖曳到此處,或: +Home--additional-content-content = 您可以將效能檢測檔拖曳到此處,或: Home--compare-recordings-info = 您也可以比較紀錄內容。開啟比較介面。 Home--your-recent-uploaded-recordings-title = 您近期上傳的紀錄 # We replace the elements such as and with links to the @@ -261,6 +261,9 @@ Home--your-recent-uploaded-recordings-title = 您近期上傳的紀錄 Home--load-files-from-other-tools2 = { -profiler-brand-name } 也可以匯入其他效能檢測器,例如 Linux perfAndroid SimplePerf、Chrome 效能面板、Android Studio 所產生的效能檢測檔、任何使用 dhat 格式Google 的 Trace Event 格式儲存的效能檢測檔。點擊此處了解如何撰寫您自己的匯入程式。 +Home--install-chrome-extension = 安裝 Chrome 擴充套件 +Home--chrome-extension-instructions = 可使用 Chrome 的 { -profiler-brand-name } 擴充套件,在 Chrome 當中捕捉效能紀錄檔,再使用 { -profiler-brand-name } 進行分析。請到 Chrome 線上應用程式安裝此套件。 +Home--chrome-extension-recording-instructions = 安裝完成後,即可使用擴充套件在工具列新增的圖示或快速鍵開始或停止捕捉效能紀錄。您也可以匯出檢測檔,匯入此處,進行更詳細的分析。 ## IdleSearchField ## The component that is used for all the search inputs in the application. @@ -339,7 +342,7 @@ MarkerFiltersContextMenu--drop-samples-outside-of-markers-matching = 丟棄不 ## This is used in all panels related to markers. MarkerSettings--panel-search = - .label = 過濾標記: + .label = 過濾標記: .title = 只顯示符合特定名稱的標記 MarkerSettings--marker-filters = .title = 標記過濾器 @@ -379,18 +382,18 @@ MenuButtons--permalink--button = ## These strings are used in the panel containing the meta information about ## the current profile. -MenuButtons--index--profile-info-uploaded-label = 上傳於: +MenuButtons--index--profile-info-uploaded-label = 上傳於: MenuButtons--index--profile-info-uploaded-actions = 刪除 MenuButtons--index--metaInfo-subtitle = 檢測檔資訊 -MenuButtons--metaInfo--symbols = 符號: +MenuButtons--metaInfo--symbols = 符號: MenuButtons--metaInfo--profile-symbolicated = 檢測檔已符號化 MenuButtons--metaInfo--profile-not-symbolicated = 檢測檔未符號化 MenuButtons--metaInfo--resymbolicate-profile = 重新將檢測檔符號化 MenuButtons--metaInfo--symbolicate-profile = 符號化檢測檔 MenuButtons--metaInfo--attempting-resymbolicate = 正在嘗試重新符號化檢測檔 MenuButtons--metaInfo--currently-symbolicating = 目前符號化的檢測檔 -MenuButtons--metaInfo--cpu-model = CPU 型號: -MenuButtons--metaInfo--cpu-cores = CPU 核心數: +MenuButtons--metaInfo--cpu-model = CPU 型號: +MenuButtons--metaInfo--cpu-cores = CPU 核心數: MenuButtons--metaInfo--main-memory = 主要記憶體: MenuButtons--index--show-moreInfo-button = 顯示更多 MenuButtons--index--hide-moreInfo-button = 顯示更少 @@ -422,11 +425,11 @@ MenuButtons--metaInfo--logical-cpu = } MenuButtons--metaInfo--profiling-started = 紀錄開始於: MenuButtons--metaInfo--profiling-session = 紀錄長度: -MenuButtons--metaInfo--main-process-started = 主處理程序開始: +MenuButtons--metaInfo--main-process-started = 主處理程序開始: MenuButtons--metaInfo--main-process-ended = 主要處理程序結束於: -MenuButtons--metaInfo--interval = 間隔: -MenuButtons--metaInfo--buffer-capacity = 緩衝容量: -MenuButtons--metaInfo--buffer-duration = 緩衝間隔: +MenuButtons--metaInfo--interval = 間隔: +MenuButtons--metaInfo--buffer-capacity = 緩衝區容量: +MenuButtons--metaInfo--buffer-duration = 緩衝區長度: # Buffer Duration in Seconds in Meta Info Panel # Variable: # $configurationDuration (Number) - Configuration Duration in Seconds @@ -437,11 +440,11 @@ MenuButtons--metaInfo--buffer-duration-seconds = # Adjective refers to the buffer duration MenuButtons--metaInfo--buffer-duration-unlimited = 無限制 MenuButtons--metaInfo--application = 應用程式 -MenuButtons--metaInfo--name-and-version = 名稱與版本: +MenuButtons--metaInfo--name-and-version = 名稱與版本: MenuButtons--metaInfo--application-uptime = 運作時間: -MenuButtons--metaInfo--update-channel = 更新頻道: -MenuButtons--metaInfo--build-id = Build ID: -MenuButtons--metaInfo--build-type = Build Type: +MenuButtons--metaInfo--update-channel = 更新頻道: +MenuButtons--metaInfo--build-id = Build ID: +MenuButtons--metaInfo--build-type = Build Type: MenuButtons--metaInfo--arguments = 參數: ## Strings refer to specific types of builds, and should be kept in English. @@ -452,20 +455,20 @@ MenuButtons--metaInfo--build-type-opt = Opt ## MenuButtons--metaInfo--platform = 平台 -MenuButtons--metaInfo--device = 裝置: +MenuButtons--metaInfo--device = 裝置: # OS means Operating System. This describes the platform a profile was captured on. -MenuButtons--metaInfo--os = OS: +MenuButtons--metaInfo--os = OS: # ABI means Application Binary Interface. This describes the platform a profile was captured on. -MenuButtons--metaInfo--abi = ABI: +MenuButtons--metaInfo--abi = ABI: MenuButtons--metaInfo--visual-metrics = 視覺指標 -MenuButtons--metaInfo--speed-index = Speed Index: +MenuButtons--metaInfo--speed-index = Speed Index: # “Perceptual” is the name of an index provided by sitespeed.io, and should be kept in English. -MenuButtons--metaInfo--perceptual-speed-index = Perceptual Speed Index: +MenuButtons--metaInfo--perceptual-speed-index = Perceptual Speed Index: # “Contentful” is the name of an index provided by sitespeed.io, and should be kept in English. -MenuButtons--metaInfo--contentful-speed-Index = Contentful Speed Index: -MenuButtons--metaInfo-renderRowOfList-label-features = 功能: -MenuButtons--metaInfo-renderRowOfList-label-threads-filter = 執行緒過濾器: -MenuButtons--metaInfo-renderRowOfList-label-extensions = 擴充套件: +MenuButtons--metaInfo--contentful-speed-Index = Contentful Speed Index: +MenuButtons--metaInfo-renderRowOfList-label-features = 功能: +MenuButtons--metaInfo-renderRowOfList-label-threads-filter = 執行緒過濾器: +MenuButtons--metaInfo-renderRowOfList-label-extensions = 擴充套件: ## Overhead refers to the additional resources used to run the profiler. ## These strings are displayed at the bottom of the "Profile Info" panel. @@ -484,9 +487,9 @@ MenuButtons--metaOverheadStatistics-statkeys-interval = 間隔 .title = 兩次計量間的間隔。 MenuButtons--metaOverheadStatistics-statkeys-lockings = 鎖定 .title = 進行計量前取得鎖定所需的時間。 -MenuButtons--metaOverheadStatistics-overhead-duration = 額外負荷持續時間: -MenuButtons--metaOverheadStatistics-overhead-percentage = 額外負荷比例: -MenuButtons--metaOverheadStatistics-profiled-duration = 檢測的持續時間: +MenuButtons--metaOverheadStatistics-overhead-duration = 額外負荷持續時間: +MenuButtons--metaOverheadStatistics-overhead-percentage = 額外負荷比例: +MenuButtons--metaOverheadStatistics-profiled-duration = 檢測的持續時間: ## Publish panel ## These strings are used in the publishing panel. @@ -520,7 +523,7 @@ MenuButtons--publish--error-while-compressing = 壓縮時發生錯誤,請嘗 ## This is used in the network chart. NetworkSettings--panel-search = - .label = 過濾網路請求: + .label = 過濾網路請求: .title = 只顯示符合某些名稱的網路請求 ## Timestamp formatting primitive @@ -633,8 +636,8 @@ StackSettings--implementation-javascript2 = JavaScript StackSettings--implementation-native2 = 原生 .title = 僅顯示原生程式碼相關的堆疊框 # This label is displayed in the marker chart and marker table panels only. -StackSettings--stack-implementation-label = 過濾堆疊: -StackSettings--use-data-source-label = 資料來源: +StackSettings--stack-implementation-label = 過濾堆疊: +StackSettings--use-data-source-label = 資料來源: StackSettings--call-tree-strategy-timing = 計時 .title = 使用紀錄到已執行的程式碼顯示摘要 StackSettings--call-tree-strategy-js-allocations = JavaScript 分配 @@ -651,7 +654,7 @@ StackSettings--invert-call-stack = 反轉呼叫堆疊 .title = 依照呼叫節點當中花費的時間排序,並忽略其 children。 StackSettings--show-user-timing = 顯示使用者計時 StackSettings--panel-search = - .label = 過濾堆疊: + .label = 過濾堆疊: .title = 只顯示包含符合的子字串的函數名稱的相關堆疊 ## Tab Bar for the bottom half of the analysis UI. @@ -716,7 +719,7 @@ TrackNameButton--hide-process = TrackMemoryGraph--relative-memory-at-this-time = 此時的相對記憶體用量 TrackMemoryGraph--memory-range-in-graph = 圖表中的記憶體範圍 -TrackMemoryGraph--allocations-and-deallocations-since-the-previous-sample = 上次取樣以來的分配予取消分配 +TrackMemoryGraph--allocations-and-deallocations-since-the-previous-sample = 上次取樣以來的分配與取消分配 ## TrackPower ## This is used to show the power used by the CPU and other chips in a computer, @@ -881,37 +884,37 @@ TransformNavigator--complete = 完成「{ $item }」 # See: https://profiler.firefox.com/docs/#/./guide-filtering-call-trees?id=collapse # Variables: # $item (String) - Name of the resource that collapsed. E.g.: libxul.so. -TransformNavigator--collapse-resource = 摺疊: { $item } +TransformNavigator--collapse-resource = 摺疊:{ $item } # "Focus subtree" transform. # See: https://profiler.firefox.com/docs/#/./guide-filtering-call-trees?id=focus # Variables: # $item (String) - Name of the function that transform applied to. -TransformNavigator--focus-subtree = 聚焦節點: { $item } +TransformNavigator--focus-subtree = 聚焦節點:{ $item } # "Focus function" transform. # See: https://profiler.firefox.com/docs/#/./guide-filtering-call-trees?id=focus # Variables: # $item (String) - Name of the function that transform applied to. -TransformNavigator--focus-function = 聚焦: { $item } +TransformNavigator--focus-function = 聚焦:{ $item } # "Focus category" transform. The word "Focus" has the meaning of an adjective here. # See: https://profiler.firefox.com/docs/#/./guide-filtering-call-trees?id=focus-category # Variables: # $item (String) - Name of the category that transform applied to. -TransformNavigator--focus-category = 聚焦於分類: { $item } +TransformNavigator--focus-category = 聚焦於分類:{ $item } # "Merge call node" transform. # See: https://profiler.firefox.com/docs/#/./guide-filtering-call-trees?id=merge # Variables: # $item (String) - Name of the function that transform applied to. -TransformNavigator--merge-call-node = 合併節點: { $item } +TransformNavigator--merge-call-node = 合併節點:{ $item } # "Merge function" transform. # See: https://profiler.firefox.com/docs/#/./guide-filtering-call-trees?id=merge # Variables: # $item (String) - Name of the function that transform applied to. -TransformNavigator--merge-function = 合併: { $item } +TransformNavigator--merge-function = 合併:{ $item } # "Drop function" transform. # See: https://profiler.firefox.com/docs/#/./guide-filtering-call-trees?id=drop # Variables: # $item (String) - Name of the function that transform applied to. -TransformNavigator--drop-function = 丟棄: { $item } +TransformNavigator--drop-function = 丟棄:{ $item } # "Collapse recursion" transform. # See: https://profiler.firefox.com/docs/#/./guide-filtering-call-trees?id=collapse # Variables: @@ -926,7 +929,7 @@ TransformNavigator--collapse-direct-recursion-only = 僅摺疊直接遞迴:{ $ # See: https://profiler.firefox.com/docs/#/./guide-filtering-call-trees?id=collapse # Variables: # $item (String) - Name of the function that transform applied to. -TransformNavigator--collapse-function-subtree = 摺疊子樹: { $item } +TransformNavigator--collapse-function-subtree = 摺疊子樹:{ $item } # "Drop samples outside of markers matching ..." transform. # Variables: # $item (String) - Search filter of the markers that transform will apply to. @@ -978,23 +981,23 @@ SourceView--no-known-cors-url = 這個檔案沒有已知的 cross-origin-accessi # Variables: # $url (String) - The URL which we tried to get the source code from # $networkErrorMessage (String) - The raw internal error message that was encountered by the network request, not localized -SourceView--network-error-when-obtaining-source = 取得網址 { $url } 時發生網路錯誤: { $networkErrorMessage } +SourceView--network-error-when-obtaining-source = 取得網址 { $url } 時發生網路錯誤:{ $networkErrorMessage } # Displayed below SourceView--cannot-obtain-source, if the browser could not # be queried for source code using the symbolication API. # Variables: # $browserConnectionErrorMessage (String) - The raw internal error message, not localized -SourceView--browser-connection-error-when-obtaining-source = 無法查詢瀏覽器的符號化 API: { $browserConnectionErrorMessage } +SourceView--browser-connection-error-when-obtaining-source = 無法查詢瀏覽器的符號化 API:{ $browserConnectionErrorMessage } # Displayed below SourceView--cannot-obtain-source, if the browser was queried # for source code using the symbolication API, and this query returned an error. # Variables: # $apiErrorMessage (String) - The raw internal error message from the API, not localized -SourceView--browser-api-error-when-obtaining-source = 瀏覽器的符號化 API 回傳錯誤: { $apiErrorMessage } +SourceView--browser-api-error-when-obtaining-source = 瀏覽器的符號化 API 回傳錯誤:{ $apiErrorMessage } # Displayed below SourceView--cannot-obtain-source, if a symbol server which is # running locally was queried for source code using the symbolication API, and # this query returned an error. # Variables: # $apiErrorMessage (String) - The raw internal error message from the API, not localized -SourceView--local-symbol-server-api-error-when-obtaining-source = 本機符號伺服器的符號化 API 回傳錯誤: { $apiErrorMessage } +SourceView--local-symbol-server-api-error-when-obtaining-source = 本機符號伺服器的符號化 API 回傳錯誤:{ $apiErrorMessage } # Displayed below SourceView--cannot-obtain-source, if the browser was queried # for source code using the symbolication API, and this query returned a malformed response. # Variables: @@ -1018,7 +1021,7 @@ SourceView--not-in-archive-error-when-obtaining-source = 下載自 { $url } 的 # Variables: # $url (String) - The URL from which the "archive" file was downloaded. # $parsingErrorMessage (String) - The raw internal error message during parsing, not localized -SourceView--archive-parsing-error-when-obtaining-source = 無法剖析下載自 { $url } 的封存檔: { $parsingErrorMessage } +SourceView--archive-parsing-error-when-obtaining-source = 無法剖析下載自 { $url } 的封存檔:{ $parsingErrorMessage } ## Toggle buttons in the top right corner of the bottom box diff --git a/package.json b/package.json index 9bc07df144..8d507c8925 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "@codemirror/lang-rust": "^6.0.1", "@codemirror/language": "^6.10.3", "@codemirror/state": "^6.4.1", - "@codemirror/view": "^6.34.2", + "@codemirror/view": "^6.35.0", "@firefox-devtools/react-contextmenu": "^5.1.1", "@fluent/bundle": "^0.18.0", "@fluent/langneg": "^0.7.0", @@ -131,10 +131,10 @@ "eslint-plugin-flowtype": "^8.0.3", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "^28.9.0", - "eslint-plugin-jest-dom": "^5.4.0", + "eslint-plugin-jest-dom": "^5.5.0", "eslint-plugin-jest-formatting": "^3.1.0", "eslint-plugin-react": "^7.37.2", - "eslint-plugin-testing-library": "^6.4.0", + "eslint-plugin-testing-library": "^6.5.0", "espree": "^10.3.0", "fake-indexeddb": "^6.0.0", "fetch-mock-jest": "^1.5.1", @@ -157,7 +157,7 @@ "open": "^10.1.0", "postcss": "^8.4.49", "postcss-loader": "^8.1.1", - "prettier": "^3.3.3", + "prettier": "^3.4.1", "raw-loader": "^4.0.2", "rimraf": "^5.0.10", "style-loader": "^4.0.0", diff --git a/res/css/global.css b/res/css/global.css index 1e9c22361b..72c99c9064 100644 --- a/res/css/global.css +++ b/res/css/global.css @@ -13,11 +13,17 @@ box-sizing: border-box; border: 0.5px solid rgb(0 0 0 / 0.1); margin-right: 3px; + + /* Opt-out of forced colors so the color is applied */ + forced-color-adjust: none; } .colored-border { border: 2px solid rgb(0 0 0 / 0.1); margin-right: 3px; + + /* Opt-out of forced colors so the color is applied */ + forced-color-adjust: none; } .colored-border.ellipsis { diff --git a/src/actions/receive-profile.js b/src/actions/receive-profile.js index 4135fe71cf..af83bc8053 100644 --- a/src/actions/receive-profile.js +++ b/src/actions/receive-profile.js @@ -1575,15 +1575,7 @@ export function retrieveProfileFromFile( // Profile files can have file names with uncommon extensions // (eg .profile). So we can't rely on the mime type to decide how to // handle them. - let arrayBuffer = await fileReader(file).asArrayBuffer(); - - // Check for the gzip magic number in the header. If we find it, decompress - // the data first. - const profileBytes = new Uint8Array(arrayBuffer); - if (isGzip(profileBytes)) { - const decompressedProfile = await decompress(profileBytes); - arrayBuffer = decompressedProfile.buffer; - } + const arrayBuffer = await fileReader(file).asArrayBuffer(); const profile = await unserializeProfileOfArbitraryFormat( arrayBuffer, diff --git a/src/app-logic/constants.js b/src/app-logic/constants.js index 2b8c1fa2fe..f80c2fdad8 100644 --- a/src/app-logic/constants.js +++ b/src/app-logic/constants.js @@ -39,12 +39,12 @@ export const TRACK_MEMORY_MARKERS_HEIGHT = 15; export const TRACK_MEMORY_HEIGHT = TRACK_MEMORY_GRAPH_HEIGHT + TRACK_MEMORY_MARKERS_HEIGHT; export const TRACK_MEMORY_LINE_WIDTH = 2; -export const TRACK_MEMORY_COLOR = 'orange'; +export const TRACK_MEMORY_DEFAULT_COLOR = 'orange'; // The following values are for the bandwidth track. export const TRACK_BANDWIDTH_HEIGHT = 25; export const TRACK_BANDWIDTH_LINE_WIDTH = 2; -export const TRACK_BANDWIDTH_COLOR = 'blue'; +export const TRACK_BANDWIDTH_DEFAULT_COLOR = 'blue'; // The following values are for experimental event delay track. export const TRACK_EVENT_DELAY_HEIGHT = 40; diff --git a/src/components/app/Home.js b/src/components/app/Home.js index 9f773179e5..08864beb0f 100644 --- a/src/components/app/Home.js +++ b/src/components/app/Home.js @@ -225,6 +225,7 @@ type PopupInstallPhase = | 'popup-enabled' | 'suggest-enable-popup' // Other browsers: + | 'suggest-chrome-extension' | 'other-browser'; class HomeImpl extends React.PureComponent { @@ -249,6 +250,10 @@ class HomeImpl extends React.PureComponent { this.setState({ popupInstallPhase: 'webchannel-unavailable' }); } ); + } else if (_isChromium()) { + popupInstallPhase = 'suggest-chrome-extension'; + // TODO: Check if the extension is installed and show the recording + // instructions. But we need to check if extension is there to do that. } this.state = { @@ -266,6 +271,8 @@ class HomeImpl extends React.PureComponent { return this._renderEnablePopupInstructions(false); case 'popup-enabled': return this._renderRecordInstructions(FirefoxPopupScreenshot); + case 'suggest-chrome-extension': + return this._renderChromeInstructions(); case 'other-browser': return this._renderOtherBrowserInstructions(); default: @@ -376,6 +383,69 @@ class HomeImpl extends React.PureComponent { ); } + _renderChromeInstructions() { + const chromeExtensionUrl = + 'https://chromewebstore.google.com/detail/firefox-profiler/ljmahpnflmbkgaipnfbpgjipcnahlghn'; + return ( + +
+ {/* Grid container: homeInstructions */} + {/* Left column: img */} + screenshot of profiler.firefox.com + {/* Right column: instructions */} +
+ + + + + Install the Chrome extension + + + + + ), + }} + > +

+ Use the Firefox Profiler extension for Chrome to capture + performance profiles in Chrome and analyze them in the Firefox + Profiler. Install the extension from the Chrome Web Store. +

+
+ +

+ Once installed, use the extension’s toolbar icon or the + shortcuts to start and stop profiling. You can also export + profiles and load them here for detailed analysis. +

+
+ {this._renderShortcuts()} +
+ {/* end of grid container */} +
+
+ ); + } + _renderRecordInstructions(screenshotSrc: string) { return ( @@ -627,6 +697,10 @@ function _isFirefox(): boolean { return Boolean(navigator.userAgent.match(/Firefox\/\d+\.\d+/)); } +function _isChromium(): boolean { + return Boolean(navigator.userAgent.match(/Chrome\/\d+\.\d+/)); +} + export const Home = explicitConnect< OwnHomeProps, StateHomeProps, diff --git a/src/components/app/MenuButtons/index.css b/src/components/app/MenuButtons/index.css index ebef647ae4..54d6557f1e 100644 --- a/src/components/app/MenuButtons/index.css +++ b/src/components/app/MenuButtons/index.css @@ -135,8 +135,8 @@ display: block; width: 32px; height: 32px; - background: url(firefox-profiler-res/img/svg/cloud-dark-12.svg) no-repeat left / - 32px; + background: url(firefox-profiler-res/img/svg/cloud-dark-12.svg) no-repeat + left / 32px; content: ''; opacity: 0.5; } diff --git a/src/components/shared/CallNodeContextMenu.css b/src/components/shared/CallNodeContextMenu.css index 3698c40b3a..5b6b61137a 100644 --- a/src/components/shared/CallNodeContextMenu.css +++ b/src/components/shared/CallNodeContextMenu.css @@ -44,3 +44,11 @@ color: #000; margin-inline-start: 12px; } + +@media (forced-colors: active) { + .callNodeContextMenuShortcut { + background: SelectedItemText; + color: SelectedItem; + outline: 1px solid CanvasText; + } +} diff --git a/src/components/shared/ContextMenu.css b/src/components/shared/ContextMenu.css index b17bc3c574..710baa2fbe 100644 --- a/src/components/shared/ContextMenu.css +++ b/src/components/shared/ContextMenu.css @@ -148,3 +148,19 @@ .react-contextmenu-item--selected > strong { color: #fff; } + +@media (forced-colors: active) { + .react-contextmenu { + border: 1px solid CanvasText; + } + + .react-contextmenu-item:not(.react-contextmenu-item--disabled):hover { + background-color: SelectedItem; + color: SelectedItemText; + } + + .react-contextmenu-item.react-contextmenu-item--disabled, + .react-contextmenu-item.react-contextmenu-item--disabled:hover { + color: GrayText; + } +} diff --git a/src/components/shared/TreeView.css b/src/components/shared/TreeView.css index 90525500a3..c7a92149a7 100644 --- a/src/components/shared/TreeView.css +++ b/src/components/shared/TreeView.css @@ -3,6 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ .treeView { + --tree-row-toggle-button-color: #888; + --tree-row-toggle-button-active-color: var(--grey-60); + --selected-tree-row-toggle-button-color: #fff; + --selected-tree-row-toggle-button-active-color: rgb(255 255 255 / 0.7); + display: flex; flex: 1; flex-flow: column nowrap; @@ -11,6 +16,15 @@ user-select: none; } +@media (forced-colors: active) { + .treeView { + --tree-row-toggle-button-color: ButtonText; + --tree-row-toggle-button-active-color: SelectedItem; + --selected-tree-row-toggle-button-color: SelectedItemText; + --selected-tree-row-toggle-button-active-color: ButtonText; + } +} + .treeViewRow, .treeViewHeader { display: flex; @@ -202,7 +216,10 @@ border-bottom: 5px solid transparent; border-left: 8px solid; margin-left: 8px; - color: #888; + color: var(--tree-row-toggle-button-color); + + /* Opt-out of forced colors so the transparent borders aren't turned into opaque ones */ + forced-color-adjust: none; } .treeRowToggleButton.expanded { @@ -216,17 +233,17 @@ } .treeRowToggleButton:active:hover { - color: var(--grey-60); + color: var(--tree-row-toggle-button-active-color); } .treeViewBody:focus .treeViewRow.isSelected > .treeRowToggleButton { - color: #fff; + color: var(--selected-tree-row-toggle-button-color); } .treeViewBody:focus .treeViewRow.isSelected > .treeRowToggleButton:active:hover { - color: rgb(255 255 255 / 0.7); + color: var(--selected-tree-row-toggle-button-active-color); } .treeRowToggleButton.leaf { diff --git a/src/components/timeline/TrackBandwidthGraph.js b/src/components/timeline/TrackBandwidthGraph.js index cec45bb179..360b3daa7b 100644 --- a/src/components/timeline/TrackBandwidthGraph.js +++ b/src/components/timeline/TrackBandwidthGraph.js @@ -33,7 +33,7 @@ import { TooltipDetailSeparator, } from 'firefox-profiler/components/tooltip/TooltipDetails'; import { EmptyThreadIndicator } from './EmptyThreadIndicator'; -import { TRACK_BANDWIDTH_COLOR } from 'firefox-profiler/app-logic/constants'; +import { TRACK_BANDWIDTH_DEFAULT_COLOR } from 'firefox-profiler/app-logic/constants'; import { getSampleIndexRangeForSelection } from 'firefox-profiler/profile-logic/profile-data'; import { co2 } from '@tgwf/co2'; @@ -142,8 +142,12 @@ class TrackBandwidthCanvas extends React.PureComponent { ctx.lineWidth = deviceLineWidth; ctx.lineJoin = 'bevel'; - ctx.strokeStyle = getStrokeColor(TRACK_BANDWIDTH_COLOR); - ctx.fillStyle = getFillColor(TRACK_BANDWIDTH_COLOR); + ctx.strokeStyle = getStrokeColor( + counter.color || TRACK_BANDWIDTH_DEFAULT_COLOR + ); + ctx.fillStyle = getFillColor( + counter.color || TRACK_BANDWIDTH_DEFAULT_COLOR + ); ctx.beginPath(); const getX = (i) => @@ -617,7 +621,9 @@ class TrackBandwidthGraphImpl extends React.PureComponent { style={{ left, top, - backgroundColor: getDotColor(TRACK_BANDWIDTH_COLOR), + backgroundColor: getDotColor( + counter.color || TRACK_BANDWIDTH_DEFAULT_COLOR + ), }} className="timelineTrackBandwidthGraphDot" /> diff --git a/src/components/timeline/TrackMemoryGraph.js b/src/components/timeline/TrackMemoryGraph.js index 6c475e3625..9e02fa9697 100644 --- a/src/components/timeline/TrackMemoryGraph.js +++ b/src/components/timeline/TrackMemoryGraph.js @@ -27,7 +27,7 @@ import { import { getThreadSelectors } from 'firefox-profiler/selectors/per-thread'; import { Tooltip } from 'firefox-profiler/components/tooltip/Tooltip'; import { EmptyThreadIndicator } from './EmptyThreadIndicator'; -import { TRACK_MEMORY_COLOR } from 'firefox-profiler/app-logic/constants'; +import { TRACK_MEMORY_DEFAULT_COLOR } from 'firefox-profiler/app-logic/constants'; import type { CounterIndex, @@ -132,8 +132,10 @@ class TrackMemoryCanvas extends React.PureComponent { ctx.lineWidth = deviceLineWidth; ctx.lineJoin = 'bevel'; - ctx.strokeStyle = getStrokeColor(TRACK_MEMORY_COLOR); - ctx.fillStyle = getFillColor(TRACK_MEMORY_COLOR); + ctx.strokeStyle = getStrokeColor( + counter.color || TRACK_MEMORY_DEFAULT_COLOR + ); + ctx.fillStyle = getFillColor(counter.color || TRACK_MEMORY_DEFAULT_COLOR); ctx.beginPath(); // The x and y are used after the loop. @@ -463,7 +465,9 @@ class TrackMemoryGraphImpl extends React.PureComponent { style={{ left, top, - backgroundColor: getDotColor(TRACK_MEMORY_COLOR), + backgroundColor: getDotColor( + counter.color || TRACK_MEMORY_DEFAULT_COLOR + ), }} className="timelineTrackMemoryGraphDot" /> diff --git a/src/components/tooltip/GCMarker.js b/src/components/tooltip/GCMarker.js index 8496b488ad..4dfb02fcb5 100644 --- a/src/components/tooltip/GCMarker.js +++ b/src/components/tooltip/GCMarker.js @@ -249,8 +249,8 @@ export function getGCMajorDetails( if (post_heap_size !== undefined) { gcsize = ( {formatBytes(timings.allocated_bytes) + ' - ' + @@ -259,7 +259,10 @@ export function getGCMajorDetails( ); } else { gcsize = ( - + {formatBytes(timings.allocated_bytes)} ); @@ -283,7 +286,26 @@ export function getGCMajorDetails( /* maxFractionalDigits */ 2 )} , - gcsize, + gcsize + ); + const pre_malloc_heap_size = timings.pre_malloc_heap_size; + const post_malloc_heap_size = timings.post_malloc_heap_size; + if ( + pre_malloc_heap_size !== undefined && + post_malloc_heap_size !== undefined + ) { + details.push( + + {formatBytes(pre_malloc_heap_size) + + ' - ' + + formatBytes(post_malloc_heap_size)} + + ); + } + details.push( {formatPercent(timings.mmu_20ms)} , diff --git a/src/components/tooltip/NetworkMarker.js b/src/components/tooltip/NetworkMarker.js index 4d63d8f1dc..db2281cf52 100644 --- a/src/components/tooltip/NetworkMarker.js +++ b/src/components/tooltip/NetworkMarker.js @@ -456,5 +456,13 @@ export function getNetworkMarkerDetails( ); } + if (payload.classOfService) { + details.push( + + {payload.classOfService} + + ); + } + return details; } diff --git a/src/profile-logic/process-profile.js b/src/profile-logic/process-profile.js index 62c38b46ce..071eb382c0 100644 --- a/src/profile-logic/process-profile.js +++ b/src/profile-logic/process-profile.js @@ -95,6 +95,7 @@ import type { MarkerPhase, Pid, } from 'firefox-profiler/types'; +import { decompress, isGzip } from 'firefox-profiler/utils/gz'; type RegExpResult = null | string[]; /** @@ -1880,7 +1881,16 @@ export async function unserializeProfileOfArbitraryFormat( if (String(arbitraryFormat) === '[object ArrayBuffer]') { // Obviously Flow doesn't understand that this is correct, so let's help // Flow here. - const arrayBuffer: ArrayBuffer = (arbitraryFormat: any); + let arrayBuffer: ArrayBuffer = (arbitraryFormat: any); + + // Check for the gzip magic number in the header. If we find it, decompress + // the data first. + const profileBytes = new Uint8Array(arrayBuffer); + if (isGzip(profileBytes)) { + const decompressedProfile = await decompress(profileBytes); + arrayBuffer = decompressedProfile.buffer; + } + if (isArtTraceFormat(arrayBuffer)) { arbitraryFormat = convertArtTraceProfile(arrayBuffer); } else { diff --git a/src/test/components/Home.test.js b/src/test/components/Home.test.js index 98ed69c88b..e53a7c79c2 100644 --- a/src/test/components/Home.test.js +++ b/src/test/components/Home.test.js @@ -24,6 +24,8 @@ const FIREFOX = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:55.0) Gecko/20100101 Firefox/55.0'; const SAFARI = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8'; +const CHROME = + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'; let userAgent; // Flow doesn't understand Object.defineProperty. Use the "any" type to use it anyway. @@ -48,6 +50,11 @@ describe('app/Home', function () { expect(container.firstChild).toMatchSnapshot(); }); + it('renders the Chrome extension instructions for Chromium based browsers', () => { + const { container } = setup(CHROME); + expect(container.firstChild).toMatchSnapshot(); + }); + it('renders the information screen for other browsers', () => { const { container } = setup(SAFARI); expect(container.firstChild).toMatchSnapshot(); diff --git a/src/test/components/TooltipMarker.test.js b/src/test/components/TooltipMarker.test.js index fd17a51ca3..7836a21051 100644 --- a/src/test/components/TooltipMarker.test.js +++ b/src/test/components/TooltipMarker.test.js @@ -210,6 +210,8 @@ describe('TooltipMarker', function () { added_chunks: 50, allocated_bytes: 48377856, post_heap_size: 38051840, + pre_malloc_heap_size: 24188928, + post_malloc_heap_size: 12683946, major_gc_number: 1, max_pause: 74.026, minor_gc_number: 16, @@ -785,6 +787,50 @@ describe('TooltipMarker', function () { expect(getValueForProperty('HTTP Version')).toBe('3'); }); + it('renders page information for pages with one class of service flag', () => { + setupWithPayload( + getNetworkMarkers({ + id: 1235, + startTime: 19000, + fetchStart: 19200.2, + endTime: 20433.8, + uri: 'https://example.org/index.html', + payload: { + cache: 'Hit', + pri: 8, + count: 47027, + contentType: 'text/html', + classOfService: 'Leader', + }, + }) + ); + + expect(getValueForProperty('Class of Service')).toBe('Leader'); + }); + + it('renders page information for pages with multiple class of service flags', () => { + setupWithPayload( + getNetworkMarkers({ + id: 1235, + startTime: 19000, + fetchStart: 19200.2, + endTime: 20433.8, + uri: 'https://example.org/index.html', + payload: { + cache: 'Hit', + pri: 8, + count: 47027, + contentType: 'text/html', + classOfService: 'Unblocked | Throttleable | TailForbidden', + }, + }) + ); + + expect(getValueForProperty('Class of Service')).toBe( + 'Unblocked | Throttleable | TailForbidden' + ); + }); + it('renders properly network markers with a preconnect part', () => { const { container } = setupWithPayload( getNetworkMarkers({ diff --git a/src/test/components/__snapshots__/Home.test.js.snap b/src/test/components/__snapshots__/Home.test.js.snap index 0d7a509d41..e196eba595 100644 --- a/src/test/components/__snapshots__/Home.test.js.snap +++ b/src/test/components/__snapshots__/Home.test.js.snap @@ -248,6 +248,273 @@ you can go to

`; +exports[`app/Home renders the Chrome extension instructions for Chromium based browsers 1`] = ` +
+
+
+

+ + + ⁨Firefox Profiler⁩ + + — + + Web app for ⁨Firefox⁩ performance analysis + + + + + + + +

+
+
+ This is a special message +
+

+ Capture a performance profile. Analyze it. Share it. Make the web faster. +

+
+
+ screenshot of profiler.firefox.com +
+ + + + + + Install the Chrome extension + + + + Documentation + +

+ Use the + + ⁨Firefox Profiler⁩ extension for Chrome + + +to capture performance profiles in Chrome and analyze them in the +⁨Firefox Profiler⁩. Install the extension from the Chrome Web Store. +

+

+ Once installed, use the extension’s +toolbar icon or the shortcuts to start and stop profiling. You can also +export profiles and load them here for detailed analysis. +

+
+

+ + Ctrl + + + + + Shift + + + + + 1 + + + Stop and start profiling +

+

+ + Ctrl + + + + + Shift + + + + + 2 + + + Capture and load profile +

+
+
+
+
+
+

+ Load existing profiles +

+
+

+ You can + + drag and drop + + a profile file here to load it, or: +

+
+
+ + + +
+
+

+ The ⁨Firefox Profiler⁩ can also import profiles from other profilers, such as + + + Linux perf + + , + + Android SimplePerf + + , the +Chrome performance panel, + + Android Studio + + , or +any file using the + + dhat format + + or + + Google’s Trace Event +Format + + . + + Learn how to write your +own importer + + . +

+

+ You can also compare recordings. + + Open the comparing interface. + +

+
+
+

+ Your recent uploaded recordings +

+ +
+
+
+
+ Drop a saved profile here +
+
+
+
+`; + exports[`app/Home renders the information screen for other browsers 1`] = `
- Heap size (pre - post) + GC heap size (pre - post) :
46.1MB - 36.3MB +
+ Malloc heap size (pre - post) + : +
+ 23.1MB - 12.1MB
diff --git a/src/test/store/receive-profile.test.js b/src/test/store/receive-profile.test.js index e49ac3122e..faae352f79 100644 --- a/src/test/store/receive-profile.test.js +++ b/src/test/store/receive-profile.test.js @@ -1559,7 +1559,7 @@ describe('actions/receive-profile', function () { const { getState, view } = await setupTestWithFile({ type: '', - payload: compress(serializeProfile(profile)), + payload: (await compress(serializeProfile(profile))).buffer, }); expect(view.phase).toBe('DATA_LOADED'); expect(ProfileViewSelectors.getProfile(getState()).meta.product).toEqual( @@ -1591,7 +1591,7 @@ describe('actions/receive-profile', function () { const { getState, view } = await setupTestWithFile({ type: 'application/gzip', - payload: compress(serializeProfile(profile)), + payload: (await compress(serializeProfile(profile))).buffer, }); expect(view.phase).toBe('DATA_LOADED'); expect(ProfileViewSelectors.getProfile(getState()).meta.product).toEqual( @@ -1605,7 +1605,7 @@ describe('actions/receive-profile', function () { const { getState, view } = await setupTestWithFile({ type: 'application/json', - payload: compress(serializeProfile(profile)), + payload: (await compress(serializeProfile(profile))).buffer, }); expect(view.phase).toBe('DATA_LOADED'); expect(ProfileViewSelectors.getProfile(getState()).meta.product).toEqual( @@ -1619,7 +1619,7 @@ describe('actions/receive-profile', function () { .mockImplementation(() => {}); const { view } = await setupTestWithFile({ type: 'application/gzip', - payload: compress('{}'), + payload: (await compress('{}')).buffer, }); expect(view.phase).toBe('FATAL_ERROR'); diff --git a/src/types/markers.js b/src/types/markers.js index e396613cfe..d83d65a29f 100644 --- a/src/types/markers.js +++ b/src/types/markers.js @@ -330,10 +330,15 @@ type GCMajorCompleted_Shared = {| // 'None' as a reason. nonincremental_reason?: 'None' | string, - // The allocated space for the whole heap before the GC started. + // The total size of GC things before and after the GC. allocated_bytes: number, post_heap_size?: number, + // The total size of malloc data owned by GC things before and after the GC. + // Added in Firefox v135 (Bug 1933205). + pre_malloc_heap_size?: number, + post_malloc_heap_size?: number, + // Only present if non-zero. added_chunks?: number, removed_chunks?: number, @@ -523,6 +528,13 @@ export type NetworkPayload = {| isPrivateBrowsing?: boolean, httpVersion?: NetworkHttpVersion, + // Used to express class dependencies and characteristics. + // Possible flags: Leader, Follower, Speculative, Background, Unblocked, + // Throttleable, UrgentStart, DontThrottle, Tail, TailAllowed, and + // TailForbidden. Multiple flags can be set, separated by '|', + // or we use 'Unset' if no flag is set. + classOfService?: string, + // NOTE: the following comments are valid for the merged markers. For the raw // markers, startTime and endTime have different meanings. Please look // `src/profile-logic/marker-data.js` for more information. diff --git a/yarn.lock b/yarn.lock index 206f3a0a3f..daaec59e90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1115,10 +1115,10 @@ resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.4.1.tgz#da57143695c056d9a3c38705ed34136e2b68171b" integrity sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A== -"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.34.2": - version "6.34.2" - resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.34.2.tgz#c6cc1387be217f448af585f05f23e681f76aeda7" - integrity sha512-d6n0WFvL970A9Z+l9N2dO+Hk9ev4hDYQzIx+B9tCyBP0W5wPEszi1rhuyFesNSkLZzXbQE5FPH7F/z/TMJfoPA== +"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.35.0": + version "6.35.0" + resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.35.0.tgz#890e8e31a58edf65cdf193049fe9f3fdec20cc82" + integrity sha512-I0tYy63q5XkaWsJ8QRv5h6ves7kvtrBWjBcnf/bzohFJQc5c14a1AQRdE8QpPF9eMp5Mq2FMm59TCj1gDfE7kw== dependencies: "@codemirror/state" "^6.4.0" style-mod "^4.1.0" @@ -5030,10 +5030,10 @@ eslint-plugin-import@^2.31.0: string.prototype.trimend "^1.0.8" tsconfig-paths "^3.15.0" -eslint-plugin-jest-dom@^5.4.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.4.0.tgz#03a5ea600f8af63f4fcd5de49ae83dc0e6aca325" - integrity sha512-yBqvFsnpS5Sybjoq61cJiUsenRkC9K32hYQBFS9doBR7nbQZZ5FyO+X7MlmfM1C48Ejx/qTuOCgukDUNyzKZ7A== +eslint-plugin-jest-dom@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.5.0.tgz#3ccdfe197eddb4108f390db583057a5dacccd4a0" + integrity sha512-CRlXfchTr7EgC3tDI7MGHY6QjdJU5Vv2RPaeeGtkXUHnKZf04kgzMPIJUXt4qKCvYWVVIEo9ut9Oq1vgXAykEA== dependencies: "@babel/runtime" "^7.16.3" requireindex "^1.2.0" @@ -5074,10 +5074,10 @@ eslint-plugin-react@^7.37.2: string.prototype.matchall "^4.0.11" string.prototype.repeat "^1.0.0" -eslint-plugin-testing-library@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-6.4.0.tgz#1ba8a7422e3e31cc315a73ff17c34908f56f9838" - integrity sha512-yeWF+YgCgvNyPNI9UKnG0FjeE2sk93N/3lsKqcmR8dSfeXJwFT5irnWo7NjLf152HkRzfoFjh3LsBUrhvFz4eA== +eslint-plugin-testing-library@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-6.5.0.tgz#02532698270f525be8ceeb4740f66eef0f6f4729" + integrity sha512-Ls5TUfLm5/snocMAOlofSOJxNN0aKqwTlco7CrNtMjkTdQlkpSMaeTCDHCuXfzrI97xcx2rSCNeKeJjtpkNC1w== dependencies: "@typescript-eslint/utils" "^5.62.0" @@ -9215,20 +9215,13 @@ minimatch@^8.0.2: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.0: +minimatch@^9.0.0, minimatch@^9.0.4: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.4: - version "9.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" - integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== - dependencies: - brace-expansion "^2.0.1" - minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -10372,10 +10365,10 @@ prettier@^2.0.5: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== -prettier@^3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" - integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== +prettier@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.1.tgz#e211d451d6452db0a291672ca9154bc8c2579f7b" + integrity sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg== pretty-bytes@^5.3.0, pretty-bytes@^5.4.1: version "5.6.0" @@ -11849,7 +11842,7 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -11867,15 +11860,6 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -11975,7 +11959,7 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -11996,13 +11980,6 @@ strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -13619,7 +13596,7 @@ workbox-window@7.3.0, workbox-window@^7.3.0: "@types/trusted-types" "^2.0.2" workbox-core "7.3.0" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -13637,15 +13614,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"