Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[system] Various perf gain experiments #23688

Merged
merged 31 commits into from Nov 26, 2020

Conversation

mnajdova
Copy link
Member

@mnajdova mnajdova commented Nov 23, 2020

Trying various micro-optimizations, nothing big found at this moment yet

@mui-pr-bot
Copy link

mui-pr-bot commented Nov 23, 2020

Details of bundle changes

Generated by 🚫 dangerJS against d68c7c0

@mnajdova

This comment has been minimized.

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Nov 23, 2020
@oliviertassinari
Copy link
Member

oliviertassinari commented Nov 23, 2020

@mnajdova What do you think about ignoring these metrics (removing them from the benchmark):

colors @material-ui/system  x 418,856 ops/sec ±2.23% (189 runs sampled)
colors styled-system x 957,951 ops/sec ±1.48% (190 runs sampled)
spaces @material-ui/system x 289,762 ops/sec ±1.25% (188 runs sampled)
spaces styled-system x 901,040 ops/sec ±1.76% (185 runs sampled)
compose @material-ui/system x 58,856 ops/sec ±0.20% (189 runs sampled)
compose styled-system x 224,670 ops/sec ±1.74% (184 runs sampled)

and focusing on the end-to-end version: @material-ui/core all-inclusive?

@oliviertassinari
Copy link
Member

oliviertassinari commented Nov 23, 2020

Trying various micro-optimizations, nothing big found at this moment yet.

@mnajdova We might want to rewrite the system to iterate on the props instead of calling each transformation. I think that Theme-UI and Chakra-UI have demonstrated that it can be faster unless it's their cache that helps the most. I think that it will make it easier to scale to custom transformations without impacting runtime cost. For instance, what if I want to add a gapX prop that adds when used.

& > * + * {
  margin-right: 8px;
}

@mbrookes a reference to #18459 (review).

@mnajdova
Copy link
Member Author

@mnajdova We might want to rewrite the system to iterate on the props instead of calling each transformation. I think that Theme-UI and Chakra-UI have demonstrated that it can be faster unless it's their cache that helps the most. I think that it will make it easier to scale to custom transformations without impacting runtime cost. For instance, what if I want to add a gapX prop that adds when used.

This is how the sx style function works right now. Let's remove from it the support for all other box props and see if there will be some perf gain. Focusing only on that one can be more productive :)

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Nov 24, 2020
@@ -26,7 +26,7 @@ export default function deepmerge<T>(
return;
}

if (isPlainObject(source[key]) && key in target) {
if (isPlainObject(source[key]) && key in target && isPlainObject(target[key])) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need deepmerge only if both source and target are objects. Otherwise we can override with source[key]

Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These look like overall improvements :).

One thing that could be interesting is to benchmark, on the Node.js side (what we call server) is the performance of the system raw, meaning sx transformation method vs. https://styled-system.com/css vs. import { css } from '@chakra-ui/styled-system'. The function that converts the superset of CSS into CSS. And remove the benchmark on the lower-level methods, like color, compose, etc.

packages/material-ui/src/Box/Box.test.js Outdated Show resolved Hide resolved
@mnajdova
Copy link
Member Author

One thing that could be interesting is to benchmark, on the Node.js side (what we call server) is the performance of the system raw, meaning sx transformation method vs. https://styled-system.com/css vs. import { css } from '@chakra-ui/styled-system'. The function that converts the superset of CSS into CSS. And remove the benchmark on the lower-level methods, like color, compose, etc.

I was trying this method already, seems like in order to be equivalent we need to run css and then the returned function. Anyway let me confirm one more time and replace the current benchmarks we have in place 👍

@mnajdova
Copy link
Member Author

Opened #23702 for updating benchmarks. Will extract PRs from this one along te way for the changes we agree are good to go :) Will keep this one as a hub for trying all changes

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Nov 25, 2020
@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Nov 26, 2020
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Nov 26, 2020
@mnajdova
Copy link
Member Author

After merging #23716 I think this can be opened as a standalone PR.

@oliviertassinari
Copy link
Member

oliviertassinari commented Nov 26, 2020

After merging #23716 I think this can be opened as a standalone PR.

@mnajdova Sounds good. I'm having a look at if I can improve the quality of the output of the benchmark test (I won't look into React.Profiler path as I know it's a direction you are already on).

}
return acc;
},
{ ...style },
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for cloning

@@ -1,4 +1,4 @@
import { deepmerge } from '@material-ui/utils';
import merge from './merge';
Copy link
Member Author

@mnajdova mnajdova Nov 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge is more suited and performant for these use-cases than deepmerge - it returns early for null args + doesn't clone the first arg.

@@ -48,25 +52,25 @@ function styleFunctionSx(props) {
let css = {};

Object.keys(styles).forEach((styleKey) => {
if (typeof styles[styleKey] === 'object') {
const value = callIfFn(styles[styleKey], theme);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was wrong previously, if the value is a function we need to resolve it and do the rest of the logic.

@@ -127,7 +127,7 @@ describe('styleFunctionSx', () => {
xl: 0.5,
},
border: [1, 2, 3],
borderColor: (t) => t.palette.secondary.main,
borderColor: (t) => [t.palette.secondary.main, t.palette.primary.main],
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated tests for the function changes implemented here https://github.com/mui-org/material-ui/pull/23688/files#r530971112

@mnajdova mnajdova marked this pull request as ready for review November 26, 2020 11:50
@mnajdova
Copy link
Member Author

mnajdova commented Nov 26, 2020

@mnajdova Sounds good. I'm having a look at if I can improve the quality of the output of the benchmark test (I won't look into React.Profiler path as I know it's a direction you are already on).

@oliviertassinari trying the React.Profiler - #23731 results don't look much more stable either... :\

@oliviertassinari
Copy link
Member

@oliviertassinari trying the React.Profiler - #23731 results don't look much more stable either... :\

I have noticed that when I switch windows during the run of the tests, I get a spike of std. Two ideas to reduce it, no idea if it works:

  • /2 the number of components mounted per measurement, x2 the number of measurements.
  • run the benchmark in a remote machine. We could maybe setup a machine in the cloud to run it from time to time.

But maybe it's already good enough. Maybe we should focus on identifying the slowest path, fix it, iterate. We can learn from existing alternative implementations.

@mnajdova
Copy link
Member Author

But maybe it's already good enough. Maybe we should focus on identifying the slowest path, fix it, iterate. We can learn from existing alternative implementations.

Agree, this first round is just about small improvements that can immediately be fixed and seems like we are now comparable with theme-ui at least.

Next, I will try to see if restructuring the whole code will make much difference, but would like to have this one in first, to compare the difference based on these new numbers

@mnajdova mnajdova merged commit 1a05bb9 into mui:next Nov 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: system Specific to @mui/system performance
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants