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

Improve tldraw example performance #640

Merged
merged 7 commits into from
Sep 12, 2023

Conversation

devleejb
Copy link
Member

@devleejb devleejb commented Sep 3, 2023

What this PR does / why we need it?

In the tldraw example project, there's long latency when moving large shapes (e.g., DrawShape).
The reason is that the unchanged data (e.g., drawing points in DrawShape) is sent when moving shapes. So, in this PR, only point data (a point of shape on the whiteboard) is sent to the Yorkie server.

Any background context you want to provide?

I was inspired by this solution.
codepair issue #194

What are the relevant tickets?

Fixes #

Checklist

  • Added relevant tests or not required
  • Didn't break anything

@CLAassistant
Copy link

CLAassistant commented Sep 3, 2023

CLA assistant check
All committers have signed the CLA.

@codecov
Copy link

codecov bot commented Sep 3, 2023

Codecov Report

Patch coverage has no change and project coverage change: -0.06% ⚠️

Comparison is base (cb4551b) 88.63% compared to head (30abe8f) 88.57%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #640      +/-   ##
==========================================
- Coverage   88.63%   88.57%   -0.06%     
==========================================
  Files          80       80              
  Lines        8894     8894              
  Branches      816      816              
==========================================
- Hits         7883     7878       -5     
- Misses        704      708       +4     
- Partials      307      308       +1     

see 1 file with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member

@krapie krapie left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution!

This was one of the highest-priority issues that Yorkie's tldraw example had.
It seems like this reduces PushPull() API's data size by several times.

I have one thing to discuss with you.

How do you think of expanding this idea to only update the shape's changes (coordinate change, style change, size change, etc) by comparing the previous shape and the updated shape?

@devleejb
Copy link
Member Author

devleejb commented Sep 4, 2023

Thank you for your comment!

Before PR, I considered about expanding this idea to only update the shape's changes. To compare difference of two object, I think it's better to use library(e.g., Lodash, deep-object-diff, ...) than implement detecting deep difference(because of complexity). And to emphasize yorkie-js-sdk's usage, I think it is appropriate not to use other libraries at most.

If you think it's okay to use a library, I'll implement it. Or, is there any idea?

@devleejb devleejb requested a review from krapie September 4, 2023 07:46
@krapie
Copy link
Member

krapie commented Sep 4, 2023

@devleejb I think it will be okay to show usage of other libraries because this will show other developers that they can use this approach to optimize the size of document updates.

How do you think of this idea, @chacha912?

@devleejb
Copy link
Member Author

devleejb commented Sep 5, 2023

@krapie
OK, I'll implement it.

I wonder what you think about this.
How about change update function in yorkie-js-sdk to ignore unchanged data?

@hackerwins hackerwins self-requested a review September 5, 2023 00:47
Copy link
Member

@hackerwins hackerwins left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution.

I understand that this PR has made some changes to use CRDT to transmit data every time a shape is moved.

I have two questions:

Can Presence be used in the tldraw example to represent the state that needs to be sent to peers who are still editing but have not completed their edits?

Additionally, is there a way to check how much improvement has been made?

@krapie
Copy link
Member

krapie commented Sep 5, 2023

How about change update function in yorkie-js-sdk to ignore unchanged data?

@devleejb It seems like a good idea, but it may be out of scope.

And like @hackerwins mentioned, it will be good to measure performance improvement.

@devleejb
Copy link
Member Author

devleejb commented Sep 5, 2023

@hackerwins

In previous tldraw example, the data is transmitted every time as same as my PR. But, in the example, when moving shapes, the unchanged data in shape object(e.g., color, point, ...) is transmitted and it made long latency. So, I send only changed data when moving shapes.

  1. Can Presence be used in the tldraw example to represent the state that needs to be sent to peers who are still editing but have not completed their edits?

    I understand that your question is that whether Presense can be used in representing editing state(e.g., moving, changing size, ...)

    Now, when moving shapes, the below information is included in doc.presence

    [
        {
            "clientID": "64f73119763112ce4175cff7",
            "presence": {
                "tdUser": {
                    "id": "0ff70062-c49b-4af7-38a2-1cb14a9a671d",
                    "color": "#07968a",
                    "point": [
                        466.64,
                        671.94
                    ],
                    "selectedIds": [
                        "fe0bcde5-009a-4927-1bae-0a3d7cec5130",
                        "bf979117-c4ce-4a91-3cb8-610d708e11a2",
                        "ec5a7d38-3364-432a-089c-06c246a61f15"
                    ],
                    "activeShapes": [],
                    "status": "connected",
                    "metadata": {
                        "name": "Anna-diane"
                    },
                    "session": true
                }
            }
        }
    ]

    There's selectedIds field. But, the data can't distinguish whether moving or changing shapes.

    I also can add new field to Presence. But, detecting user's editing state can be calculated in onChangePage function.

  2. Is there a way to check how much improvement has been made?

    I think that it can be achieved using comparison of latency.

    For test, I moved drawing shape.

    Previous PushPullChanges Response Time
    227ms
    283ms
    326ms
    ...
    Previous PushPullChanges Response Time
    15ms
    15ms
    16ms
    ...

    The latency is decreased. And the decreasing rate is different for shape size.
    The screenshot is in this URL

@hackerwins
Copy link
Member

For sharing purposes, the information @devleejb left in the comment is also left here.

Example:
drawing example

Before:
before

After:
after

@Jaeheon-Sim
Copy link

Jaeheon-Sim commented Sep 6, 2023

@devleejb
This improvement is truly what I wanted, Thank you!
But, I found an error in this PR

In this code, the Tldraw deletion element is not reflected in Yorkie.

How about applying this code?

Before:

 if (isMoving) {
            root.shapes[id].point = shape?.point;
            return;
          }

After:

if (isMoving && shape?.point) {
            root.shapes[id].point = shape?.point;
            return;
          }

OR

Deleted thing's shape is null when OnChangePage is working .
So, how about detect it on first step?
like...

 doc.update((root) => {

           if (!shape) { // delete element
                delete root.shapes[id];
                return;
           }
          const rootShapePoint = root.shapes[id]?.toJS?.().point;
          const isMoving =
            root.shapes[id] &&
            JSON.stringify(rootShapePoint) !== JSON.stringify(shape?.point);

          if (isMoving) { // move element
            root.shapes[id].point = shape?.point as Array<number>;
            return;
          }

          // create element
           root.shapes[id] = shape;
          
        });

This can detect deleted elements on Tldraw

Thank you!!

@devleejb
Copy link
Member Author

devleejb commented Sep 6, 2023

@Jaeheon-Sim
Thank you for your comment.

I added code for deleting shape.

Thank for your help.

Copy link
Member

@krapie krapie left a comment

Choose a reason for hiding this comment

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

@devleejb The latency improvement will become larger as we move more shapes simultaneously. (When I measured latency improvement by moving 20 shapes by 1 pixel, latency improved 35ms to 8ms).

How do you think of expanding this idea to only update the shape's changes (coordinate change, style change, size change, etc) by comparing the previous shape and the updated shape?

After you implement this idea, please let me know.

@devleejb
Copy link
Member Author

devleejb commented Sep 7, 2023

@krapie

I implemented your idea by comparing changed property in object.

Thank you.

@devleejb devleejb requested a review from krapie September 7, 2023 16:27
Copy link
Member

@krapie krapie left a comment

Choose a reason for hiding this comment

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

Thank you for implementing this idea!
It will be good to test performance of this idea with previous ones.

Also, I left a small comment below.

@devleejb devleejb requested a review from krapie September 8, 2023 13:09
@devleejb
Copy link
Member Author

devleejb commented Sep 8, 2023

@krapie

I removed it. Thank you!

Copy link
Member

@krapie krapie left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution.
Looks good to me 👍🏼

Copy link
Member

@hackerwins hackerwins left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution.

@hackerwins hackerwins merged commit 876d3dc into yorkie-team:main Sep 12, 2023
2 checks passed
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

5 participants