Docs
Performance
JS/WASM Benchmarks

JS/WASM Benchmarks

The primary role of these benchmarks should be to serve as indicators of the absence of performance pitfalls rather than as measures of which project is superior. This is because different projects consistently make different trade-offs. It is inaccurate to claim that Project A is superior to Project B simply because A performs better in certain benchmarks, while Project B may excel in other areas by a significant margin.

The benchmark can be reproduced using the crdt-benchmarks (opens in a new tab) repo.

  • The benchmarks were performed on MacBook Pro M1 2020 with 16GB RAM
  • loro-old is the version of loro on 2023-11-10, it's compiled from this commit (opens in a new tab). Loro has undergone numerous changes since then, particularly in terms of encoding schema (opens in a new tab), shifting from a performance-focused version to one that prioritizes compatibility. Because we want Loro to have good backward and forward compatibility after reaching version 1.0, we have adopted a more easily extensible encoding method. It is slower than the encoding method used in the loro-old version, but it better ensures our ability to iterate quickly after reaching version 1.0 without introducing breaking changes.
  • There is a more exchaustive benchmark at the bottom that only runs benchmarks on Yjs.
  • Automerge can perform the B4 benchmark in about 1 second (see time) if all changes are applied within a single change transaction. However, our benchmarks test individual edits that generate individual update events as this more closely simulates actual user behavior. See #21
  • Note that parseTime is significantly higher with automerge and loro when the initial document is not empty (e.g. when syncing content from a remote server).
  • Loro and Automerge can store a complete DAG of editing history for each keystroke, but Yjs requires additional storage for a Version Vector + Delete Set for each version saved, which incurs significant extra overhead beyond the document size reported.
Benchmark setup

B1: No conflicts

Simulate two clients. One client modifies a text object and sends update messages to the other client. We measure the time to perform the task (time), the amount of data exchanged (avgUpdateSize), the size of the encoded document after the task is performed (docSize), the time to parse the encoded document (parseTime), and the memory used to hold the decoded document (memUsed).

B2: Two users producing conflicts

Simulate two clients. Both start with a synced text object containing 100 characters. Both clients modify the text object in a single transaction and then send their changes to the other client. We measure the time to sync concurrent changes into a single client (time), the size of the update messages (updateSize), the size of the encoded document after the task is performed (docSize), the time to parse the encoded document (parseTime), and the memory used to hold the decoded document (memUsed).

B3: Many conflicts

Simulate √N concurrent actions. We measure the time to perform the task and sync all clients (time), the size of the update messages (updateSize), the size of the encoded document after the task is performed (docSize), the time to parse the encoded document (parseTime), and the memory used to hold the decoded document (memUsed). The logarithm of N was chosen because √N concurrent actions may result in up to √N^2 - 1 conflicts (apply action 1: 0 conflict; apply action2: 1 conflict, apply action 2: 2 conflicts, ..).

B4: Real-world editing dataset

Replay a real-world editing dataset. This dataset contains the character-by-character editing trace of a large-ish text document, the LaTeX source of this paper: https://arxiv.org/abs/1608.03960 (opens in a new tab)

Source: https://github.com/automerge/automerge-perf/tree/master/edit-by-index (opens in a new tab)

  • 182,315 single-character insertion operations
  • 77,463 single-character deletion operations
  • 259,778 operations totally
  • 104,852 characters in the final document

We simulate one client replaying all changes and storing each update. We measure the time to replay the changes and the size of all update messages (updateSize), the size of the encoded document after the task is performed (docSize), the time to encode the document (encodeTime), the time to parse the encoded document (parseTime), and the memory used to hold the decoded document in memory (memUsed).

[B4 x 100] Real-world editing dataset 100 times

Replay the [B4] dataset one hundred times. The final document has a size of over 10 million characters. As comparison, the book "Game of Thrones: A Song of Ice and Fire" is only 1.6 million characters long (including whitespace).

  • 18,231,500 single-character insertion operations
  • 7,746,300 single-character deletion operations
  • 25,977,800 operations totally
  • 10,485,200 characters in the final document
N = 6000yjsywasmloroloro-oldautomergeautomerge-wasm
Version13.6.150.17.41.0.0-beta.20.15.22.1.100.9.0
Bundle size84,017 bytes938,991 bytes2,919,363 bytes1,583,094 bytes1,696,176 bytes1,701,136 bytes
Bundle size (gzipped)25,105 bytes284,616 bytes894,460 bytes592,039 bytes591,049 bytes594,071 bytes
[B1.1] Append N characters (time)141 ms171 ms164 ms115 ms279 ms110 ms
[B1.1] Append N characters (avgUpdateSize)27 bytes27 bytes88 bytes58 bytes121 bytes121 bytes
[B1.1] Append N characters (encodeTime)1 ms0 ms3 ms0 ms5 ms6 ms
[B1.1] Append N characters (docSize)6,031 bytes6,031 bytes12,382 bytes6,219 bytes3,992 bytes3,992 bytes
[B1.1] Append N characters (memUsed)0 B0 B0 B0 B0 B0 B
[B1.1] Append N characters (parseTime)22 ms65 ms28 ms28 ms59 ms61 ms
[B1.2] Insert string of length N (time)1 ms1 ms0 ms0 ms18 ms14 ms
[B1.2] Insert string of length N (avgUpdateSize)6,031 bytes6,031 bytes6,089 bytes6,088 bytes6,201 bytes6,201 bytes
[B1.2] Insert string of length N (encodeTime)0 ms0 ms0 ms0 ms2 ms2 ms
[B1.2] Insert string of length N (docSize)6,031 bytes6,031 bytes12,313 bytes6,146 bytes3,974 bytes3,974 bytes
[B1.2] Insert string of length N (parseTime)27 ms47 ms27 ms26 ms29 ms30 ms
[B1.3] Prepend N characters (time)118 ms30 ms111 ms47 ms272 ms73 ms
[B1.3] Prepend N characters (avgUpdateSize)27 bytes26 bytes87 bytes57 bytes116 bytes116 bytes
[B1.3] Prepend N characters (encodeTime)2 ms0 ms2 ms1 ms4 ms4 ms
[B1.3] Prepend N characters (docSize)6,041 bytes6,040 bytes15,414 bytes6,165 bytes3,988 bytes3,988 bytes
[B1.3] Prepend N characters (parseTime)45 ms38 ms27 ms37 ms73 ms47 ms
[B1.4] Insert N characters at random positions (time)128 ms101 ms113 ms51 ms268 ms89 ms
[B1.4] Insert N characters at random positions (avgUpdateSize)29 bytes29 bytes88 bytes58 bytes121 bytes121 bytes
[B1.4] Insert N characters at random positions (encodeTime)3 ms0 ms2 ms1 ms6 ms5 ms
[B1.4] Insert N characters at random positions (docSize)29,571 bytes29,554 bytes39,040 bytes29,503 bytes24,743 bytes24,743 bytes
[B1.4] Insert N characters at random positions (parseTime)46 ms30 ms27 ms26 ms73 ms64 ms
[B1.5] Insert N words at random positions (time)149 ms264 ms112 ms54 ms539 ms291 ms
[B1.5] Insert N words at random positions (avgUpdateSize)36 bytes36 bytes95 bytes65 bytes131 bytes131 bytes
[B1.5] Insert N words at random positions (encodeTime)6 ms1 ms3 ms1 ms14 ms15 ms
[B1.5] Insert N words at random positions (docSize)87,868 bytes87,924 bytes135,713 bytes98,901 bytes96,203 bytes96,203 bytes
[B1.5] Insert N words at random positions (parseTime)50 ms33 ms27 ms33 ms101 ms111 ms
[B1.6] Insert string, then delete it (time)1 ms0 ms2 ms1 ms39 ms31 ms
[B1.6] Insert string, then delete it (avgUpdateSize)6,053 bytes6,052 bytes6,189 bytes6,179 bytes6,338 bytes6,338 bytes
[B1.6] Insert string, then delete it (encodeTime)0 ms0 ms0 ms0 ms3 ms2 ms
[B1.6] Insert string, then delete it (docSize)6,040 bytes6,039 bytes6,409 bytes6,145 bytes3,993 bytes3,993 bytes
[B1.6] Insert string, then delete it (parseTime)29 ms29 ms26 ms28 ms52 ms44 ms
[B1.7] Insert/Delete strings at random positions (time)153 ms112 ms136 ms60 ms423 ms212 ms
[B1.7] Insert/Delete strings at random positions (avgUpdateSize)31 bytes31 bytes100 bytes61 bytes135 bytes135 bytes
[B1.7] Insert/Delete strings at random positions (encodeTime)3 ms1 ms3 ms1 ms13 ms11 ms
[B1.7] Insert/Delete strings at random positions (docSize)41,917 bytes41,592 bytes81,700 bytes51,470 bytes59,281 bytes59,281 bytes
[B1.7] Insert/Delete strings at random positions (parseTime)53 ms41 ms25 ms27 ms80 ms78 ms
[B1.8] Append N numbers (time)140 ms59 ms155 ms73 ms448 ms113 ms
[B1.8] Append N numbers (avgUpdateSize)32 bytes32 bytes94 bytes62 bytes125 bytes125 bytes
[B1.8] Append N numbers (encodeTime)2 ms0 ms2 ms2 ms6 ms6 ms
[B1.8] Append N numbers (docSize)35,641 bytes35,634 bytes71,568 bytes47,625 bytes26,985 bytes26,985 bytes
[B1.8] Append N numbers (parseTime)32 ms43 ms31 ms29 ms76 ms67 ms
[B1.9] Insert Array of N numbers (time)3 ms3 ms13 ms9 ms47 ms22 ms
[B1.9] Insert Array of N numbers (avgUpdateSize)35,653 bytes35,657 bytes35,715 bytes35,717 bytes31,199 bytes31,199 bytes
[B1.9] Insert Array of N numbers (encodeTime)1 ms0 ms2 ms1 ms4 ms2 ms
[B1.9] Insert Array of N numbers (docSize)35,653 bytes35,657 bytes71,578 bytes47,646 bytes26,953 bytes26,953 bytes
[B1.9] Insert Array of N numbers (parseTime)43 ms29 ms31 ms29 ms56 ms44 ms
[B1.10] Prepend N numbers (time)157 ms31 ms125 ms53 ms484 ms159 ms
[B1.10] Prepend N numbers (avgUpdateSize)32 bytes32 bytes93 bytes61 bytes120 bytes120 bytes
[B1.10] Prepend N numbers (encodeTime)3 ms1 ms3 ms1 ms6 ms6 ms
[B1.10] Prepend N numbers (docSize)35,669 bytes35,665 bytes76,773 bytes47,645 bytes26,987 bytes26,987 bytes
[B1.10] Prepend N numbers (parseTime)53 ms33 ms48 ms39 ms65 ms67 ms
[B1.11] Insert N numbers at random positions (time)160 ms121 ms125 ms56 ms517 ms121 ms
[B1.11] Insert N numbers at random positions (avgUpdateSize)34 bytes34 bytes94 bytes60 bytes125 bytes125 bytes
[B1.11] Insert N numbers at random positions (encodeTime)2 ms1 ms4 ms1 ms8 ms6 ms
[B1.11] Insert N numbers at random positions (docSize)59,132 bytes59,137 bytes100,632 bytes70,901 bytes47,746 bytes47,746 bytes
[B1.11] Insert N numbers at random positions (parseTime)52 ms50 ms58 ms41 ms428 ms80 ms
[B2.1] Concurrently insert string of length N at index 0 (time)1 ms0 ms1 ms0 ms75 ms32 ms
[B2.1] Concurrently insert string of length N at index 0 (updateSize)6,094 bytes6,094 bytes6,188 bytes9,244 bytes9,499 bytes9,499 bytes
[B2.1] Concurrently insert string of length N at index 0 (encodeTime)0 ms0 ms0 ms0 ms7 ms5 ms
[B2.1] Concurrently insert string of length N at index 0 (docSize)12,151 bytes12,151 bytes24,735 bytes12,281 bytes8,011 bytes8,011 bytes
[B2.1] Concurrently insert string of length N at index 0 (parseTime)28 ms34 ms30 ms27 ms60 ms48 ms
[B2.2] Concurrently insert N characters at random positions (time)46 ms166 ms55 ms125 ms270 ms399 ms
[B2.2] Concurrently insert N characters at random positions (updateSize)33,420 bytes33,444 bytes23,779 bytes350,337 bytes27,476 bytes1,093,293 bytes
[B2.2] Concurrently insert N characters at random positions (encodeTime)2 ms1 ms4 ms1 ms6 ms11 ms
[B2.2] Concurrently insert N characters at random positions (docSize)66,808 bytes66,852 bytes79,937 bytes59,358 bytes50,686 bytes50,704 bytes
[B2.2] Concurrently insert N characters at random positions (parseTime)67 ms69 ms27 ms27 ms51 ms95 ms
[B2.3] Concurrently insert N words at random positions (time)105 ms459 ms68 ms120 ms435 ms630 ms
[B2.3] Concurrently insert N words at random positions (updateSize)89,143 bytes88,994 bytes62,640 bytes408,723 bytes122,485 bytes1,185,202 bytes
[B2.3] Concurrently insert N words at random positions (encodeTime)7 ms2 ms7 ms3 ms28 ms35 ms
[B2.3] Concurrently insert N words at random positions (docSize)178,428 bytes178,130 bytes268,884 bytes197,284 bytes185,019 bytes191,498 bytes
[B2.3] Concurrently insert N words at random positions (parseTime)82 ms67 ms31 ms30 ms134 ms184 ms
[B2.4] Concurrently insert & delete (time)145 ms1,243 ms118 ms282 ms653 ms1,311 ms
[B2.4] Concurrently insert & delete (updateSize)140,984 bytes141,122 bytes123,725 bytes798,123 bytes298,810 bytes2,395,876 bytes
[B2.4] Concurrently insert & delete (encodeTime)6 ms3 ms14 ms4 ms43 ms56 ms
[B2.4] Concurrently insert & delete (docSize)282,112 bytes282,358 bytes392,151 bytes304,592 bytes293,831 bytes307,291 bytes
[B2.4] Concurrently insert & delete (parseTime)105 ms73 ms34 ms31 ms185 ms269 ms
[B3.1] 20√N clients concurrently set number in Map (time)54 ms60 ms27 ms32 ms1,058 ms21 ms
[B3.1] 20√N clients concurrently set number in Map (updateSize)49,167 bytes49,162 bytes132,376 bytes63,832 bytes283,296 bytes283,296 bytes
[B3.1] 20√N clients concurrently set number in Map (encodeTime)3 ms1 ms16 ms1 ms9 ms12 ms
[B3.1] 20√N clients concurrently set number in Map (docSize)36,763 bytes36,751 bytes78,764 bytes38,428 bytes86,165 bytes86,164 bytes
[B3.1] 20√N clients concurrently set number in Map (parseTime)57 ms67 ms83 ms49 ms59 ms54 ms
[B3.2] 20√N clients concurrently set Object in Map (time)55 ms62 ms27 ms40 ms1,126 ms28 ms
[B3.2] 20√N clients concurrently set Object in Map (updateSize)85,084 bytes85,073 bytes171,370 bytes99,753 bytes398,090 bytes325,370 bytes
[B3.2] 20√N clients concurrently set Object in Map (encodeTime)2 ms1 ms18 ms2 ms21 ms17 ms
[B3.2] 20√N clients concurrently set Object in Map (docSize)72,682 bytes72,659 bytes84,255 bytes75,227 bytes112,588 bytes93,401 bytes
[B3.2] 20√N clients concurrently set Object in Map (parseTime)73 ms68 ms83 ms48 ms68 ms59 ms
[B3.3] 20√N clients concurrently set String in Map (time)124 ms61 ms63 ms73 ms1,869 ms166 ms
[B3.3] 20√N clients concurrently set String in Map (updateSize)7,826,229 bytes7,826,225 bytes7,912,520 bytes7,840,917 bytes8,063,440 bytes8,063,440 bytes
[B3.3] 20√N clients concurrently set String in Map (encodeTime)56 ms5 ms70 ms23 ms59 ms61 ms
[B3.3] 20√N clients concurrently set String in Map (docSize)7,813,826 bytes7,813,814 bytes241,646 bytes7,815,537 bytes97,997 bytes98,008 bytes
[B3.3] 20√N clients concurrently set String in Map (parseTime)141 ms75 ms161 ms44 ms80 ms76 ms
[B3.4] 20√N clients concurrently insert text in Array (time)45 ms49 ms195 ms28 ms1,768 ms19 ms
[B3.4] 20√N clients concurrently insert text in Array (updateSize)52,751 bytes52,735 bytes137,490 bytes70,514 bytes311,830 bytes285,330 bytes
[B3.4] 20√N clients concurrently insert text in Array (encodeTime)1 ms0 ms13 ms1 ms13 ms7 ms
[B3.4] 20√N clients concurrently insert text in Array (docSize)26,596 bytes26,580 bytes100,791 bytes47,943 bytes96,423 bytes86,519 bytes
[B3.4] 20√N clients concurrently insert text in Array (parseTime)55 ms37 ms94 ms30 ms43 ms37 ms
[B4] Apply real-world editing dataset (time)2,616 ms17,556 ms2,271 ms768 ms7,109 ms2,775 ms
[B4] Apply real-world editing dataset (encodeTime)4 ms8 ms11 ms3 ms165 ms161 ms
[B4] Apply real-world editing dataset (docSize)226,981 bytes226,981 bytes230,556 bytes260,813 bytes129,116 bytes129,116 bytes
[B4] Apply real-world editing dataset (parseTime)27 ms22 ms6 ms4 ms1,185 ms1,123 ms
[B4x100] Apply real-world editing dataset 100 times (time)279,705 msskipped233,739 ms75,122 msskippedskipped
[B4x100] Apply real-world editing dataset 100 times (encodeTime)417 msskipped743 ms205 msskippedskipped
[B4x100] Apply real-world editing dataset 100 times (docSize)22,694,543 bytesskipped21,016,454 bytes26,826,427 bytesskippedskipped
[B4x100] Apply real-world editing dataset 100 times (parseTime)1,270 msskipped66 ms200 msskippedskipped
[B3.5] 20√N clients concurrently insert text (time)42 ms49 ms212 ms115 ms1,869 ms36 ms
[B3.5] 20√N clients concurrently insert text (updateSize)48,129 bytes48,135 bytes132,870 bytes68,978 bytes298,020 bytes298,020 bytes
[B3.5] 20√N clients concurrently insert text (encodeTime)1 ms0 ms13 ms1 ms12 ms16 ms
[B3.5] 20√N clients concurrently insert text (docSize)24,313 bytes24,325 bytes102,818 bytes48,053 bytes90,768 bytes90,781 bytes
[B3.5] 20√N clients concurrently insert text (parseTime)38 ms38 ms64 ms63 ms67 ms55 ms
[C1.1] Concurrently insert & delete 100K (time)27,138 msskipped2,335 msskipped50,692 msskipped
[C1.1] Concurrently insert & delete 100K (updateSize)4,908,122 bytesskipped4,269,521 bytesskipped10,326,487 bytesskipped
[C1.1] Concurrently insert & delete 100K (encodeTime)129 msskipped210 msskipped837 msskipped
[C1.1] Concurrently insert & delete 100K (docSize)4,908,186 bytesskipped6,748,052 bytesskipped5,404,289 bytesskipped
[C1.1] Concurrently insert & delete 100K (parseTime)1,653 msskipped78 msskipped7,308 msskipped
[C1.1] Concurrently insert & delete 100K (versionSize)222,681 bytesskipped28 bytesskipped64 bytesskipped
[C1.2] Concurrently set Map 100K (time)31,598 msskipped488 msskipped472,547 msskipped
[C1.2] Concurrently set Map 100K (updateSize)980,804 bytesskipped2,601,744 bytesskipped5,541,744 bytesskipped
[C1.2] Concurrently set Map 100K (encodeTime)60 msskipped203 msskipped2,652 msskipped
[C1.2] Concurrently set Map 100K (docSize)738,949 bytesskipped1,539,209 bytesskipped1,743,081 bytesskipped
[C1.2] Concurrently set Map 100K (parseTime)4,069 msskipped631 msskipped338 msskipped
[C1.2] Concurrently set Map 100K (versionSize)416,246 bytesskipped314,810 bytesskipped1,949,999 bytesskipped