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

StringDictionarySlim instead of Dictionary/StructDictionary #554

Merged
merged 3 commits into from
Nov 15, 2018

Conversation

lahma
Copy link
Collaborator

@lahma lahma commented Nov 13, 2018

I have replaced the StructDictionary with slightly modified DictionarySlim. This version uses string keys directly (hence the name StringDictionarySlim) and doesn't check for collisions as we don't need to detect multi-threaded access.

I also removed separate dictionary _intrinsicProperties as so far I've seen need, we can probably add back later if needed.

Performance results generally seem to be within the waving my laptop does, but the greatest benefit can be seen in UncacheableExpressionsBenchmark where more realistic object mapping happens against the new dictionary type.

Esprima.Benchmark.DromaeoBenchmark

Diff Method FileName Mean Gen 0/1k Op Gen 1/1k Op Gen 2/1k Op Allocated Memory/Op
Old Run dromaeo-3d-cube 72.63 ms 1250.0000 250.0000 - 7366 KB
New 71.86 ms (-1%) 1285.7143 (+3%) 285.7143 (+14%) - 7269.35 KB (-1%)
Old Run dromaeo-core-eval 14.60 ms 62.5000 - - 297.95 KB
New 14.78 ms (+1%) 62.5000 (0%) - - 297.64 KB (0%)
Old Run dromaeo-object-array 162.35 ms 42000.0000 1750.0000 750.0000 178311.04 KB
New 162.25 ms (0%) 42000.0000 (0%) 1750.0000 (0%) 750.0000 (0%) 178093.47 KB (0%)
Old Run droma(...)egexp [21] 869.95 ms 51000.0000 29000.0000 19000.0000 412014.58 KB
New 877.92 ms (+1%) 53000.0000 (+4%) 34000.0000 (+17%) 21000.0000 (+11%) 412072.82 KB (0%)
Old Run droma(...)tring [21] 1,174.86 ms 219000.0000 176000.0000 173000.0000 1392945.34 KB
New 1,161.21 ms (-1%) 217000.0000 (-1%) 175000.0000 (-1%) 173000.0000 (0%) 1391455.03 KB (0%)

Jint.Benchmark.ArrayBenchmark

Diff Method N Mean Gen 0/1k Op Gen 1/1k Op Gen 2/1k Op Allocated Memory/Op
Old Slice 100 429.3 us 161.1328 - - 660.16 KB
New 448.7 us (+5%) 160.6445 (0%) - - 659.38 KB (0%)
Old Concat 100 461.8 us 175.7813 - - 720.31 KB
New 459.2 us (-1%) 175.2930 (0%) - - 718.75 KB (0%)
Old Unshift 100 18,291.9 us 3562.5000 - - 14672.66 KB
New 18,704.0 us (+2%) 3562.5000 (0%) - - 14671.88 KB (0%)
Old Push 100 10,113.7 us 343.7500 - - 1438.28 KB
New 9,788.8 us (-3%) 343.7500 (0%) - - 1437.5 KB (0%)
Old Index 100 11,500.0 us 390.6250 - - 1637.5 KB
New 11,142.1 us (-3%) 390.6250 (0%) - - 1636.72 KB (0%)
Old Map 100 2,635.9 us 488.2813 - - 2011.72 KB
New 2,547.8 us (-3%) 488.2813 (0%) - - 2009.38 KB (0%)
Old Apply 100 603.4 us 188.4766 - - 774.22 KB
New 593.6 us (-2%) 188.4766 (0%) - - 773.44 KB (0%)
Old JsonStringifyParse 100 4,598.3 us 1273.4375 - - 5242.19 KB
New 4,522.7 us (-2%) 1273.4375 (0%) - - 5233.59 KB (0%)
Old FilterWithString 100 28,951.9 us 3187.5000 - - 13182.81 KB
New 28,481.0 us (-2%) 3187.5000 (0%) - - 13180.47 KB (0%)

Jint.Benchmark.UncacheableExpressionsBenchmark

Diff Method N Mean Gen 0/1k Op Gen 1/1k Op Gen 2/1k Op Allocated Memory/Op
Old Benchmark 500 287.9 ms 33500.0000 - - 135.1 MB
New 250.4 ms (-13%) 29500.0000 (-12%) - - 119.66 MB (-11%)

@lahma lahma changed the title StringDictionarySlim instead of Dictionary/StructDictionary WIP StringDictionarySlim instead of Dictionary/StructDictionary Nov 13, 2018
@lahma lahma changed the title WIP StringDictionarySlim instead of Dictionary/StructDictionary StringDictionarySlim instead of Dictionary/StructDictionary Nov 15, 2018
@@ -18,8 +19,7 @@ namespace Jint.Native.Object
{
public class ObjectInstance : JsValue, IEquatable<ObjectInstance>
{
protected Dictionary<string, PropertyDescriptor> _intrinsicProperties;
protected internal Dictionary<string, PropertyDescriptor> _properties;
internal StringDictionarySlim<PropertyDescriptor> _properties;
Copy link
Owner

Choose a reason for hiding this comment

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

Why a single dictionary now? Didn't I do two dictionaries on purpose?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Well I couldn't find the reason to have separate _intrinsicProperties, tried to read the ECMA spec and it doesn't have such distinction. Symbolic properties work the same way as normal properties etc.

Copy link
Owner

Choose a reason for hiding this comment

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

I think it might be for iterating. Pretty sure it was necessary.

Copy link
Owner

Choose a reason for hiding this comment

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

Let's see how it goes without it then, next time I think something matters I'll write a unit test ;)

_properties?.Clear();
_intrinsicProperties?.Clear();

_properties = null;
Copy link
Owner

Choose a reason for hiding this comment

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

Wasn't the goal here to reuse the same instance?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The new data type doesn't support Clear, didn't make much of a difference as you can see from perf report. ArgumentsInstances are the big polluters as they were created for function calls, might not have properties materialized that often.

Copy link
Owner

Choose a reason for hiding this comment

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

You can only say if you run a diff with and without ;)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Shouldn't be hard to implement, will add.

Jint/Collections/HashHelpers.cs Outdated Show resolved Hide resolved
* HashHelpers to StringDictionarySlim
@@ -298,14 +301,14 @@ public JsValue Freeze(JsValue thisObject, JsValue[] arguments)
{
if (desc.Writable)
{
var mutable = desc as PropertyDescriptor ?? new PropertyDescriptor(desc);
Copy link
Owner

Choose a reason for hiding this comment

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

Why aren't we cloning it anymore? Are these immutable?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

R# showed that this will never be evaluated, every property descriptor is a PropertyDescriptor..

* support Clear
@sebastienros sebastienros merged commit dc2ce8c into sebastienros:dev Nov 15, 2018
@lahma lahma deleted the perf/DictionarySlim branch November 15, 2018 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants