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

Replace CompactValue with StyleValueHandle and StyleValuePool #1534

Closed
wants to merge 1 commit into from

Conversation

NickGerleman
Copy link
Contributor

@NickGerleman NickGerleman commented Dec 23, 2023

Summary

Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from CompactValue (a customized 32-bit float with tag bits), to StyleValuePool.

This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer.

This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements).

Before After Δ
sizeof(yoga::Style) 208B 144B -64B/-31%
sizeof(yoga::Node) 640B 576B -64B/-10%
sizeof(YogaLayoutableShadowNode) 920B 856B -64B/-7%
sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps) 1296B 1168B -128B/-10%
sizeof(ViewShadowNode) 920B 856B -64B/-7%
sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps) 2000B 1872B -128B/-6%

Differential Revision: D52223122

Test Plan

Added new unit tests, and existing ones pass.

Perf in Yoga microbenchmark was supposedly a good amount better due to less memory usage, but I'm wanting to benchmark this more thoroughly alongside other changes.

Copy link

vercel bot commented Dec 23, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
yoga-website-next ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 4, 2024 9:53am

@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D52223122

NickGerleman added a commit to NickGerleman/yoga that referenced this pull request Dec 23, 2023
Summary:


| | Before | After | Δ |
| `sizeof(yoga::Style)` | 208B  | 144B | -64B/-31% |
| `sizeof(yoga::Node)` | 640B  | 576B | -64B/-10% |
| `sizeof(YogaLayoutableShadowNode) ` |  920B | 856B | -64B/-7% |
| `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B  | 1168B | -128B/-10% |
| `sizeof(ViewShadowNode)`  |  920B | 856B | -64B/-7% |
| `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B  | 1872B | -128B/-6% |

Differential Revision: D52223122
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D52223122

NickGerleman added a commit to NickGerleman/react-native that referenced this pull request Jan 3, 2024
Summary:
X-link: facebook/yoga#1534

Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from `CompactValue` (a customized 32-bit float with tag bits), to `StyleValuePool`.

This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer.

This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements).

| | Before | After | Δ |
| `sizeof(yoga::Style)` | 208B  | 144B | -64B/-31% |
| `sizeof(yoga::Node)` | 640B  | 576B | -64B/-10% |
| `sizeof(YogaLayoutableShadowNode) ` |  920B | 856B | -64B/-7% |
| `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B  | 1168B | -128B/-10% |
| `sizeof(ViewShadowNode)`  |  920B | 856B | -64B/-7% |
| `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B  | 1872B | -128B/-6% |

Differential Revision: D52223122
NickGerleman added a commit to NickGerleman/yoga that referenced this pull request Jan 3, 2024
…ok#1534)

Summary:

Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from `CompactValue` (a customized 32-bit float with tag bits), to `StyleValuePool`.

This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer.

This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements).

| | Before | After | Δ |
| `sizeof(yoga::Style)` | 208B  | 144B | -64B/-31% |
| `sizeof(yoga::Node)` | 640B  | 576B | -64B/-10% |
| `sizeof(YogaLayoutableShadowNode) ` |  920B | 856B | -64B/-7% |
| `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B  | 1168B | -128B/-10% |
| `sizeof(ViewShadowNode)`  |  920B | 856B | -64B/-7% |
| `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B  | 1872B | -128B/-6% |

Differential Revision: D52223122
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D52223122

NickGerleman added a commit to NickGerleman/react-native that referenced this pull request Jan 3, 2024
Summary:
X-link: facebook/yoga#1534

Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from `CompactValue` (a customized 32-bit float with tag bits), to `StyleValuePool`.

This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer.

This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements).

| | Before | After | Δ |
| `sizeof(yoga::Style)` | 208B  | 144B | -64B/-31% |
| `sizeof(yoga::Node)` | 640B  | 576B | -64B/-10% |
| `sizeof(YogaLayoutableShadowNode) ` |  920B | 856B | -64B/-7% |
| `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B  | 1168B | -128B/-10% |
| `sizeof(ViewShadowNode)`  |  920B | 856B | -64B/-7% |
| `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B  | 1872B | -128B/-6% |

Differential Revision: D52223122
NickGerleman added a commit to NickGerleman/yoga that referenced this pull request Jan 3, 2024
…ok#1534)

Summary:

Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from `CompactValue` (a customized 32-bit float with tag bits), to `StyleValuePool`.

This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer.

This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements).

| | Before | After | Δ |
| `sizeof(yoga::Style)` | 208B  | 144B | -64B/-31% |
| `sizeof(yoga::Node)` | 640B  | 576B | -64B/-10% |
| `sizeof(YogaLayoutableShadowNode) ` |  920B | 856B | -64B/-7% |
| `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B  | 1168B | -128B/-10% |
| `sizeof(ViewShadowNode)`  |  920B | 856B | -64B/-7% |
| `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B  | 1872B | -128B/-6% |

Differential Revision: D52223122
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D52223122

@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D52223122

NickGerleman added a commit to NickGerleman/yoga that referenced this pull request Jan 4, 2024
…ok#1534)

Summary:
X-link: facebook/react-native#42131


Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from `CompactValue` (a customized 32-bit float with tag bits), to `StyleValuePool`.

This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer.

This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements).

| | Before | After | Δ |
| `sizeof(yoga::Style)` | 208B  | 144B | -64B/-31% |
| `sizeof(yoga::Node)` | 640B  | 576B | -64B/-10% |
| `sizeof(YogaLayoutableShadowNode) ` |  920B | 856B | -64B/-7% |
| `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B  | 1168B | -128B/-10% |
| `sizeof(ViewShadowNode)`  |  920B | 856B | -64B/-7% |
| `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B  | 1872B | -128B/-6% |

Differential Revision: D52223122
NickGerleman added a commit to NickGerleman/react-native that referenced this pull request Jan 4, 2024
…ok#42131)

Summary:

X-link: facebook/yoga#1534

Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from `CompactValue` (a customized 32-bit float with tag bits), to `StyleValuePool`.

This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer.

This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements).

| | Before | After | Δ |
| `sizeof(yoga::Style)` | 208B  | 144B | -64B/-31% |
| `sizeof(yoga::Node)` | 640B  | 576B | -64B/-10% |
| `sizeof(YogaLayoutableShadowNode) ` |  920B | 856B | -64B/-7% |
| `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B  | 1168B | -128B/-10% |
| `sizeof(ViewShadowNode)`  |  920B | 856B | -64B/-7% |
| `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B  | 1872B | -128B/-6% |

Differential Revision: D52223122
…ok#1534)

Summary:
X-link: facebook/react-native#42131


Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from `CompactValue` (a customized 32-bit float with tag bits), to `StyleValuePool`.

This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer.

This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements).

| | Before | After | Δ |
| `sizeof(yoga::Style)` | 208B  | 144B | -64B/-31% |
| `sizeof(yoga::Node)` | 640B  | 576B | -64B/-10% |
| `sizeof(YogaLayoutableShadowNode) ` |  920B | 856B | -64B/-7% |
| `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B  | 1168B | -128B/-10% |
| `sizeof(ViewShadowNode)`  |  920B | 856B | -64B/-7% |
| `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B  | 1872B | -128B/-6% |

Differential Revision: D52223122
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D52223122

NickGerleman added a commit to NickGerleman/react-native that referenced this pull request Jan 4, 2024
…ok#42131)

Summary:

X-link: facebook/yoga#1534

Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from `CompactValue` (a customized 32-bit float with tag bits), to `StyleValuePool`.

This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer.

This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements).

| | Before | After | Δ |
| `sizeof(yoga::Style)` | 208B  | 144B | -64B/-31% |
| `sizeof(yoga::Node)` | 640B  | 576B | -64B/-10% |
| `sizeof(YogaLayoutableShadowNode) ` |  920B | 856B | -64B/-7% |
| `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B  | 1168B | -128B/-10% |
| `sizeof(ViewShadowNode)`  |  920B | 856B | -64B/-7% |
| `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B  | 1872B | -128B/-6% |

Differential Revision: D52223122
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D52223122

@NickGerleman NickGerleman changed the title ValuePool Replace CompactValue with StyleValueHandle and StyleValuePool Jan 4, 2024
facebook-github-bot pushed a commit to facebook/litho that referenced this pull request Jan 20, 2024
Summary:
X-link: facebook/react-native#42131

X-link: facebook/yoga#1534

Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from `CompactValue` (a customized 32-bit float with tag bits), to `StyleValuePool`.

This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer.

This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements).

This does seem to make style reads slower, which due to their heavy frequency, does have a performance impact observable by synthetics. In an example laying out a tree of 10,000 nodes, we originally read from `StyleValuePool` 2.4 million times.

This originally resulted in a ~10% regression, but when combined with the changes in the last diff, most style reads become simple bitwise operations on the handle, and we are actually 14% faster than before.

| | Before | After | Δ |
| `sizeof(yoga::Style)` | 208B  | 144B | -64B/-31% |
| `sizeof(yoga::Node)` | 640B  | 576B | -64B/-10% |
| `sizeof(YogaLayoutableShadowNode) ` |  920B | 856B | -64B/-7% |
| `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B  | 1168B | -128B/-10% |
| `sizeof(ViewShadowNode)`  |  920B | 856B | -64B/-7% |
| `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B  | 1872B | -128B/-6% |
| "Huge nested layout" microbenchmark (M1 Ultra) | 11.5ms | 9.9ms | -1.6ms/-14% |
| Quest Store C++ heap usage (avg over 10 runs) | 86.2MB | 84.9MB | -1.3MB/-1.5% |

Reviewed By: joevilches

Differential Revision: D52223122

fbshipit-source-id: 990f4b7e991e8e22d198ce20f7da66d9c6ba637b
@facebook-github-bot
Copy link
Contributor

This pull request has been merged in 67154d4.

facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Jan 20, 2024
Summary:
Pull Request resolved: #42131

X-link: facebook/yoga#1534

Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from `CompactValue` (a customized 32-bit float with tag bits), to `StyleValuePool`.

This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer.

This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements).

This does seem to make style reads slower, which due to their heavy frequency, does have a performance impact observable by synthetics. In an example laying out a tree of 10,000 nodes, we originally read from `StyleValuePool` 2.4 million times.

This originally resulted in a ~10% regression, but when combined with the changes in the last diff, most style reads become simple bitwise operations on the handle, and we are actually 14% faster than before.

| | Before | After | Δ |
| `sizeof(yoga::Style)` | 208B  | 144B | -64B/-31% |
| `sizeof(yoga::Node)` | 640B  | 576B | -64B/-10% |
| `sizeof(YogaLayoutableShadowNode) ` |  920B | 856B | -64B/-7% |
| `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B  | 1168B | -128B/-10% |
| `sizeof(ViewShadowNode)`  |  920B | 856B | -64B/-7% |
| `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B  | 1872B | -128B/-6% |
| "Huge nested layout" microbenchmark (M1 Ultra) | 11.5ms | 9.9ms | -1.6ms/-14% |
| Quest Store C++ heap usage (avg over 10 runs) | 86.2MB | 84.9MB | -1.3MB/-1.5% |

Reviewed By: joevilches

Differential Revision: D52223122

fbshipit-source-id: 990f4b7e991e8e22d198ce20f7da66d9c6ba637b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants