Coder Social home page Coder Social logo

firefox-devtools / profiler Goto Github PK

View Code? Open in Web Editor NEW
1.1K 39.0 363.0 60.45 MB

Firefox Profiler — Web app for Firefox performance analysis

Home Page: https://profiler.firefox.com

License: Mozilla Public License 2.0

CSS 2.26% JavaScript 81.08% HTML 0.57% Shell 0.04% Fluent 16.03% Dockerfile 0.01% Python 0.01%
firefox javascript react redux performance profiler gecko-profiler devtools

profiler's Introduction

Firefox Profiler

Matrix

The Firefox Profiler visualizes performance data recorded from web browsers. It is a tool designed to consume performance profiles from the Gecko Profiler but can visualize data from any profiler able to output in JSON. The interface is a web application built using React and Redux and runs entirely client-side.

Mozilla develops this tool to help make Firefox silky smooth and fast for millions of its users, and to help make sites and apps faster across the web.

Screenshot of the Firefox Profiler

Usage

Visit profiler.firefox.com 🚀

This project is live on https://profiler.firefox.com/. The website includes instructions on how to get going to start recording and viewing performance profiles.

Accessibility: Assistive technology support

The Profiler was tested with recent versions of the following assistive technology:

NVDA (Windows) on Firefox and Chrome browsers
VoiceOver (Mac OS X) on Chrome
Orca (Linux) on Firefox

If you experience problems using any of the above technologies, please file a bug.

If you would like to help us test on other assistive technologies or improve the existing code, we would love your contributions!

Development

You will need a recent enough version of Yarn 1 (Classic), version 1.10 is known to work correctly. You can install it using npm install -g yarn. Please refer to its documentation for other possible install procedures.

To download and build the Firefox Profiler web app run:

git clone [email protected]:firefox-devtools/profiler.git
cd profiler
yarn install
yarn start

Flow is used for type checking. VSCode users can install the "Flow Language Support" extension, and disable VSCode's built-in TypeScript extension in the workspace via the setup instructions here.

You can also develop the Firefox Profiler online in a pre-configured development environment.

Open in Gitpod

Please look at our gitpod documentation for more information.

For more detailed information on getting started contributing. We have plenty of docs available to get you started.

Contributing Find out in detail how to get started and get your local development environment configured.
Code of Conduct We want to create an open and inclusive community, we have a few guidelines to help us out.
Developer Documentation Want to know how this whole thing works? Get started here.
Source Files Dive into the inner workings of the code. Most folders have a README.md providing more information.
End-User Documentation These docs are customized for actual users of the profiler, not just folks contributing.
Gitpod documentatation Start here if you want to set up a work space on gitpod.

Discussion

Say hello on Matrix in the Firefox Profiler channel (#profiler:mozilla.org).

License

MPL v2 is designed to encourage contributors to share modifications they make to the code, while still allowing them to combine the code with code under other licenses (open or proprietary) with minimal restrictions.

We are very grateful to the the zlib compression library (Jean-loup Gailly, Mark Adler and team) for their contribution to the project.

profiler's People

Contributors

andy-moz avatar artpoli avatar brisad avatar canaltinova avatar canova avatar ciphergirl avatar dependabot[bot] avatar depfu[bot] avatar edieblu avatar fjoerfoks avatar fqueze avatar gregtatum avatar gribnoysup avatar ihorhordiichuk avatar jimsp472000 avatar julienw avatar karm46 avatar kazarmy avatar koehlermichael avatar marceloghelman avatar markh-bz avatar mstange avatar parttimenerd avatar paulbone avatar petercpg avatar ravmn avatar theochevalier avatar zirisut avatar zoepage avatar zubialevich avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

profiler's Issues

Get information about installed add-ons from the profiled Firefox instance

This will require changes to the Gecko Profiler add-on.

The old addon + old cleopatra do this, and I think it's quite nice: In the call tree, for any JS frames that executed code in an add-on's JS file, we show the add-on's name and its icon in that tree row.

We should do the same in the new add-on + the new cleopatra.

We can also use this information to draw pie charts about the code that is running in a certain selected range, for example.

Explore worker architecture

Dealing with profile data on the main thread does not scale when the data scales. This work should be done in a thread to not block the UI. Ideally the abstraction should work like talking to a server using XHR to get the necessary data.

There is some existing work here:
https://github.com/mstange/cleopatra/blob/cleopatra-react/src/symbol-store-db.js#L129-L134
Then the worker script is:
https://github.com/mstange/cleopatra/blob/cleopatra-react/src/symbol-store-db-worker.js

And then code that wants to use SymbolStoreDB can either use SymbolStoreDB or SymbolStoreDBThreaded depending on whether it wants the code to be executed on the main thread or in a worker.

This talk has some useful information on multi-threaded architectures: https://www.youtube.com/watch?v=CciUEEkqHXU

Accept URLs of zipped profiles

Add a URL scheme that allows for a paramater to a URL with a zip file (on an https host with appropriate CORS headers). On load, display the list of files in the zip archive and allow selecting one, and then display the selected profile.

This is used by our talos profiling infrastructure. If you push to try with mozharness: --spsProfile, then on treeherder the resulting talos jobs will have links to view the collected profiles directly in cleopatra. Each talos subtest collects multiple profiles and puts them into one zip file.

Add a "top functions" call tree view

In a "top functions" view, all functions are displayed in a flat list (no tree structure), sorted by "inclusive time", i.e. sorted by the number of samples where this function is present anywhere on the stack.

Example:

Normal:

total self
19    -     (root)
19    -       RunLoop
10    -         ProcessCircles
10    2           ProcessElement
 8    8             Circle::Circumference()
 9    -         ProcessSquares
 9    3           ProcessElement
 6    6             Square::Circumference()

Inverted:

total self
8     8     Circle::Circumference()
8     -       ProcessElement
8     -         ProcessCircles
8     -           RunLoop
8     -             (root)
6     6     Square::Circumference()
6     -       ProcessElement
6     -         ProcessSquares
6     -           RunLoop
6     -             (root)
5     5     ProcessElement
5     -       ProcessSquares
5     -         RunLoop
5     -           (root)
5     -       ProcessCircles
5     -         RunLoop
5     -           (root)

Top functions:

total self
19    -     (root)
19    -     RunLoop
19    5     ProcessElement
10    -     ProcessCircles
 9    -     ProcessSquares
 8    8     Circle::Circumference()
 6    6     Square::Circumference()

I think we should have such a mode. We could make it a different mode inside the existing Call Tree tab, or we could have a new tab for it.

In addition, from each function, it should be possible to:

  1. Restrict the profile to only show samples that contained this function in the stack
  2. Do the inverse of 1, i.e. remove all samples containing this function in the stack
  3. Look at the call tree of functions called by the selected function
  4. Look at the (inverted) call tree of functions that call the selected function

For example, we could split the tab three ways: the list on the left, and two tree views on the right, above each other, with the upper one showing 3 and the lower one showing 4.

┆Issue is synchronized with this Jira Task

Where to store tab-specific state?

At the moment, the state of the two checkboxes "JavaScript only" and "Invert call stack" is reflected in the URL as query params. However, these settings only affect a single tab, the "Call Tree" tab. When the user switches to a different tab, e.g. to the "Markers" tab, should those parts of the URL stick around? As we add more tabs with their own settings, it can potentially get quite crowded in the URL.

We can't just throw the state away on tab switch - losing state as you switch back and forth between tabs would be extremely frustrating. We also can't remove all tab-specific state from the URL completely, because that would mean that you lose the ability to share a specific view of a profile with others.

The only other idea I have is that we could have tab-specific settings of the current tab in the URL, and tab-specific settings of inactive tabs in the redux state. Then, on tab switch, we would put the state of the newly selected tab into the URL again. However, that might be a little too much magic... It would also mean that if you share the URL of you current profile view with somebody, the cleopatra instance on the other person's machine will only know about the view settings of the current tab, and switching tabs will potentially show different views to them than to you.

Summarize Profile View

I was talking with sfink about his needs, and he was wanting a top summary view of a profile that shows where time was being executed so that it would be really easy to point a finger at performance problems to specific parties.

This gist contains his existing Python script for performing this analysis. He admitted the categorization is a bit hacky, so maybe this could tie into Cleopatra's own categorization system.

Support focusing on a function

Add a context menu item to the call tree that allows you to restrict the profile to only callstacks that contain the selected function, regardless of the ancestor callstack of the selected tree row.

Add some kind of tab bar

We'll have different ways of looking at a profile, and different types of data and data representations. A tab bar seems like the easiest way to switch between these views.

Pick colors for different Gecko components

E.g. gfx could be green, dom blue, GC pink ...

We will have many places where we want to show a breakdown of the types of code that are running, and we can use a consistent color scheme to convey this information. For example in the tree view, in the icon column that will show favicons or addon icons for JS frames, we can have a generic icon of a certain component's color for C++ functions from that component. Or we can have a CPU usage graph at the top (like the one in the Chrome devtools) that shows has different fill colors depending on what component's code was at the top of the stack at a certain time. Or for a certain selected range, we can show a pie chart of what components were busy during that range.

Add a flame graph tab

This should support selecting functions and profile filtering similar to what the call tree supports.

Add conversion code for old profile formats

The profile format has changed a few times. For loading shared profiles, we need to support all the traditional formats. I'm aware of four:

  1. The "inflated" raw profile format
  2. The "deduplicated" raw profile format
  3. The "inflated" + "profileJSONWithSymbolicationTable,1" format
  4. The "preprocessed" profile format

There was also a plain text format before the first JSON format, but I don't think anything is still using that.

Format 1 is what nsIProfiler used to return before bug 1154115. Format 2 is what nsIProfiler returns since bug 1154115.
The old addon still expects format 1 as its input, so it has code to convert format 2 to format 1.
Format 3 is what the old addon sends to the old cleopatra. It's similar to format 1 but has one more level of object wrapping around it, and a format: "profileJSONWithSymbolicationTable,1" annotation.

The new addon does not do any format conversion and just forwards format 2 from nsIProfiler directly to cleopatra. So at the moment, the new cleopatra only supports format 2 as input. It then converts it to format 4, in src/preprocess-profile.js.

Truncated ObjC symbols in XUL

-[ToolbarWindow sendEvent should be -[ToolbarWindow sendEvent:], and -[ChildView handleMouseMoved should be -[ChildView handleMouseMoved:].

Break up CSS code into multiple files

We should have one CSS file per React component that the given styles apply to.

We can also try using CSS variables as some kind of public interface of a component's styles. Then the generic styles can go into the component's stylesheet, and styles that are specific to a particular use of the component go into the parent component's stylesheet.

[Locally Stored Profiles] Automatically store the profile locally after receiving it from the addon

When perf.html is opened from the Gecko Profiler addon, it should take the profile it received, store it in IndexedDB, generate an ID for it, and set the URL to /local/theGeneratedId/. And it should support loading the profile from IndexedDB when such a URL is navigated to.

The goal is to survive a browser restart without losing your state, even if you haven't shared the profile publicly.

Some of the problems we'll need to solve as part of this:

  • Expiration / quota management
  • Wait for symbolication to complete or no?
  • How to generate the ID? The web app that stores published profiles generates a hash of the contents, but if we store the profile before we've finished symbolication, then the contents can change; should we keep updating the hash and the URL in that case?

┆Issue is synchronized with this Jira Task

Support focusing a call stack

In the call tree, for each row add an arrow button that allows you to restrict the profile to the subtree under the selected call stack prefix.
This needs to be implemented in such a way that, when you're in JS-only mode, you can focus on a JS call stack, and then switch off JS-only mode to see the C++ call graph under the selected JS stack. This can be a little tricky because there might be many C++ call stack prefixes that reduce to the selected JS call stack prefix.

Add an FPS graph to the Timeline

The marker timeline and the jank markers already let you see when we painted and how long that took, and whether the thread was available for painting at all or busy doing something else (janking). But a line graph of the FPS might be a more useful visualization in some cases, especially if you're looking at a long running profile and are not zoomed in enough to care about individual paints.

We could have a line graph that displays both theoretical max FPS (based on the "responsiveness" information from the profile samples) and actual FPS, overlaid on top of each other. Maybe we should put both the content process and the parent process into the same graph. The parent process usually manages a higher theoretical FPS than the content process, so if we pick the right drawing order and the right colors (+ fill or no fill), it might not look too overwhelming.

┆Issue is synchronized with this Jira Task

Add a markers list

Aside from displaying markers in the thread's timeline, we should also have a list of all the markers, maybe in a separate tab.

JIT Information Discussion

JIT information is gathered in the profiles and this should be displayed for analysis.

Overview

I'm working on understanding how all of this works, so this is a summary of my understanding at this point, which may not be 100% correct. JavaScript strings go through the parser and then are turned into machine code. This is then run by the interpreter. From there the code goes to baseline where instrumentation is added so that the polymorphic nature of JavaScript can be analyzed for how it is actually being used. The Ion Monkey compiler is much more strict and implements certain strategies for accessing data in a monomorphic manner, thus it is much more optimized and quick since it doesn't have to include additional overhead of extensive checks for data types. However, if this optimized code is called with differently shaped data, then this optimization can fail. This is a bail out, and the code has to go back down to Ion Monkey, which is a performance cost of converting that data back down to baseline.

JIT Information in Profiler

I probably need to hunt down more specifics about the data exposed about the JIT, but it takes the form of a list of decisions associated with individual frames, like the following.

  • strategy -> failure code
  • strategy -> failure code
  • strategy -> success

There is a huge amount of information with the JIT, and we don't want developers to waste their time on optimizing code that doesn't warrant this micro-optimizations. The following metrics are probably useful for exposing in views.

JIT De-Optimization Rank

We care about hot functions that are executed frequently, and we care about optimization failures that actually affect performance. Thus we have two different metrics.

  • Time spent executing code
  • The impact of JIT de-optimizations

The most offending code that should be targeted for optimizations then is the code that has both spent a lot of time executing, and that has bad JIT de-optimizations. Any code that doesn't fit these cases should be ignored.

Bail-Out Rate

Bail outs are bad for Ion code. There is an expensive cost of moving from Ion to baseline. In addition this means that code that is probably hot has moved back to baseline which is slower. Surfacing bail-outs for function calls would probably be a useful metric for finding code that is de-optimized and slowing things down. I'm not sure if this means bail-out rates for individual functions would be useful, or maybe the total sum.

Where does this information live? Would this only be available in tracelogger, or is it already exposed in the gecko profiler?

Baseline vs Ion

Finally it would be helpful to see how much time code is actually spending in baseline vs Ion. This information is probably only availabe through tracelogger.

Raw JIT Information

Probably the most dangerous for over-analysis is the individual JIT information associated with each frame. This is currently exposed in the performance devtools under flags, and should be accessible as well.

Prior art

Add a log tab

When the profiler is active, printf_stderr writes both to stderr and to the profile. (Search for set_stderr_callback to see how it does this.)

We should have a log tab that just shows you the plaintext stderr output.

Confusing information hierarchy

Selecting a row in the Call Tree tab will make the thread stack graph light up, but that graph is outside the tab. When you switch tabs, it will stay lit up.
Checking "JavaScript only" in the Call Tree tab also affects the thread stack graph, and that effect will persist as you switch tabs.

This is confusing. I think we should make everything above the tab bar not be affected by tab-specific settings. One way to do that would be to:

  • Replace the thread stack graphs with graphs that display rolling average category activity.
  • Inside the call tree tab, display the thread stack graph for the selected thread

Move the two checkboxes in the call tree tab from the sidebar into a bar at the top

The sidebar is taking up a lot more space than it needs. Having just two checkboxes next to each other above the tree view should be enough. Then we can also add a filter search field in that bar. And since we want to move the thread stack graphs into the tab itself (see #41), having the full width available means that the timelines can match up with the graphs above the tab bar.

Changing URL from /from-addon/ to /public/.../ destroys the world

This is because the router replaces ProfileViewerWithDataFromAddon with ProfileViewerWithDataFromWeb due to the URL change. This causes the ProfileSharingCompositeButton to lose its state and to not open the permalink panel. It also causes the call tree tree view to grab focus.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.