Last active
January 22, 2025 20:27
-
-
Save JobLeonard/dedb07499cfa289b94d686bde05901df to your computer and use it in GitHub Desktop.
Generator vs iterable "Duff's Device-based" coroutine, don't benchmark iterator creation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"title":"Generator vs iterable \"Duff's Device-based\" coroutine, don't benchmark iterator creation","initialization":"// Idiomatic JS: use function* syntax, which creates\n// an object that follows the iterable protocol. See:\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol\nfunction* actor() {\n const data = {x: 0, y: 0 };\n while (data.x < 10000) {\n data.x += 1;\n yield data;\n }\n while (data.y < 10000) {\n data.y += 1;\n yield data;\n }\n while (data.x > 0) {\n data.x -= 1;\n yield data;\n }\n while (data.y > 0) {\n data.y -= 1;\n yield data;\n }\n yield data;\n}\n\n// state + switch trick taken from:\n// https://www.chiark.greenend.org.uk/%7Esgtatham/coroutines.html\nclass Actor {\n #done;\n #value;\n #state;\n constructor() {\n this.#done = false;\n this.#value = { x: 0, y: 0 };\n this.#state = 0;\n }\n next() {\n let done = this.#done, value = this.#value;\n switch (this.#state) {\n case 0:\n value.x += 1;\n if (value.x >= 10000) this.#state = 1;\n return {done, value};\n case 1:\n value.y += 1;\n if (value.y >= 10000) this.#state = 2;\n return {done, value};\n case 2:\n value.x -= 1;\n if (value.x <= 0) this.#state = 3;\n return {done, value};\n case 3:\n value.y -= 1;\n if (value.y <= 0) {\n done = this.#done = true;\n this.#state = 4;\n }\n return {done, value};\n case 4:\n default:\n return {done, value};\n }\n }\n [Symbol.iterator]() {\n return this;\n }\n}\n\nclass ActorReturnSelf {\n done;\n value;\n #state;\n constructor() {\n this.done = false;\n this.value = { x: 0, y: 0 };\n this.#state = 0;\n }\n next() {\n const v = this.value;\n switch (this.#state) {\n case 0:\n v.x += 1;\n if (v.x >= 10000) this.#state = 1;\n return this;\n case 1:\n v.y += 1;\n if (v.y >= 10000) this.#state = 2;\n return this;\n case 2:\n v.x -= 1;\n if (v.x <= 0) this.#state = 3;\n return this;\n case 3:\n v.y -= 1;\n if (v.y <= 0) {\n this.done = true;\n this.#state = 4;\n }\n return this\n case 4:\n default:\n return this;\n }\n }\n [Symbol.iterator]() {\n return this;\n }\n}\n\nclass ActorNotIterable {\n constructor() {\n this.state = 0;\n this.data = { x: 0, y: 0 };\n this.done = false;\n }\n next() {\n const data = this.data;\n switch (this.state) {\n case 0:\n data.x += 1;\n if (data.x >= 10000) this.state = 1;\n return data;\n case 1:\n data.y += 1;\n if (data.y >= 10000) this.state = 2;\n return data;\n case 2:\n data.x -= 1;\n if (data.x <= 0) this.state = 3;\n return data;\n case 3:\n data.y -= 1;\n if (data.y <= 0) {\n this.state = 4;\n this.done = true;\n }\n case 4:\n default:\n return data;\n }\n }\n}\n\nclass ActorNotIterable2 {\n constructor() {\n this.state = 1;\n this.data = { x: 0, y: 0 };\n }\n next() {\n const data = this.data;\n switch (this.state) {\n case 1:\n data.x += 1;\n if (data.x >= 10000) this.state = 2;\n return data;\n case 2:\n data.y += 1;\n if (data.y >= 10000) this.state = 3;\n return data;\n case 3:\n data.x -= 1;\n if (data.x <= 0) this.state = 4;\n return data;\n case 4:\n data.y -= 1;\n if (data.y <= 0) this.state = 0;\n return data;\n case 0:\n default:\n return data;\n }\n }\n}","setup":"const i_actor = actor();\nconst i_class = new Actor();\nconst i_rs = new ActorReturnSelf();\nconst i_ni = new ActorNotIterable();\nconst i_ni2 = new ActorNotIterable2();\n\nlet ret = {x: 0, y: 0};","tests":[{"name":"function* based, for..of loop","code":"for (const k of i_actor) {\n ret = k;\n}\n\n","results":{"aborted":false,"count":609411,"cycles":7,"hz":7836412.883839089,"stats":{"moe":3.0175034413367086e-9,"rme":2.364640284471977,"sem":1.5395425721105657e-9,"deviation":1.2024211874871043e-8,"mean":1.276094068578602e-7,"variance":1.445816712117898e-16,"numSamples":61},"times":{"cycle":0.07776657624265544,"elapsed":6.411,"period":1.276094068578602e-7,"timeStamp":1737577605252}},"platforms":{"Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0":{"aborted":false,"count":1362671,"cycles":8,"hz":17119197.31290545,"stats":{"moe":7.010067717476585e-10,"rme":1.200067324323104,"sem":3.57656516197785e-10,"deviation":2.838810589923251e-9,"mean":5.8413953745725085e-8,"variance":8.058845565460395e-18,"numSamples":63},"times":{"cycle":0.07959900076464095,"elapsed":6.204,"period":5.8413953745725085e-8,"timeStamp":1737558658755}},"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36":{"aborted":false,"count":5811703,"cycles":8,"hz":74541829.21331346,"stats":{"moe":5.079744710281156e-11,"rme":0.3786534626410104,"sem":2.5917064848373246e-11,"deviation":2.0895005688695317e-10,"mean":1.341528656532346e-8,"variance":4.3660126273060966e-20,"numSamples":65},"times":{"cycle":0.07796566117755005,"elapsed":5.991,"period":1.341528656532346e-8,"timeStamp":1737558737979}},"Mozilla/5.0 (Android 11; Mobile; rv:134.0) Gecko/134.0 Firefox/134.0":{"aborted":false,"count":609411,"cycles":7,"hz":7836412.883839089,"stats":{"moe":3.0175034413367086e-9,"rme":2.364640284471977,"sem":1.5395425721105657e-9,"deviation":1.2024211874871043e-8,"mean":1.276094068578602e-7,"variance":1.445816712117898e-16,"numSamples":61},"times":{"cycle":0.07776657624265544,"elapsed":6.411,"period":1.276094068578602e-7,"timeStamp":1737577605252}}}},{"name":"function* based, while(!res.done) loop","code":"const iter = i_actor;\nlet res = iter.next();\nwhile(!res.done) {\n ret = res.value;\n res = iter.next();\n}","results":{"aborted":false,"count":641300,"cycles":11,"hz":8447121.30868918,"stats":{"moe":4.1160999853867185e-10,"rme":0.3476919589525537,"sem":2.1000510129524076e-10,"deviation":1.6535818211813738e-9,"mean":1.1838352539951619e-7,"variance":2.734332839341509e-18,"numSamples":62},"times":{"cycle":0.07591935483870974,"elapsed":6.31,"period":1.1838352539951619e-7,"timeStamp":1737577611736}},"platforms":{"Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0":{"aborted":false,"count":1466478,"cycles":9,"hz":18599585.1449668,"stats":{"moe":8.374235918037337e-10,"rme":1.5575731398157466,"sem":4.272569345937417e-10,"deviation":3.3369833349396417e-9,"mean":5.376464002857656e-8,"variance":1.1135457777664892e-17,"numSamples":61},"times":{"cycle":0.0788446617798269,"elapsed":6.114,"period":5.376464002857656e-8,"timeStamp":1737558664965}},"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36":{"aborted":false,"count":7028887,"cycles":10,"hz":88757786.56300907,"stats":{"moe":1.8108350897733798e-10,"rme":1.60725714398913,"sem":9.2389545396601e-11,"deviation":7.333192825851559e-10,"mean":1.1266617146768312e-8,"variance":5.377571702112078e-19,"numSamples":63},"times":{"cycle":0.07919177879689687,"elapsed":6.06,"period":1.1266617146768312e-8,"timeStamp":1737558743976}},"Mozilla/5.0 (Android 11; Mobile; rv:134.0) Gecko/134.0 Firefox/134.0":{"aborted":false,"count":641300,"cycles":11,"hz":8447121.30868918,"stats":{"moe":4.1160999853867185e-10,"rme":0.3476919589525537,"sem":2.1000510129524076e-10,"deviation":1.6535818211813738e-9,"mean":1.1838352539951619e-7,"variance":2.734332839341509e-18,"numSamples":62},"times":{"cycle":0.07591935483870974,"elapsed":6.31,"period":1.1838352539951619e-7,"timeStamp":1737577611736}}}},{"name":"Class based, for..of loop","code":"for (const k of i_class) {\n ret = k;\n}","results":{"aborted":false,"count":2074878,"cycles":7,"hz":26809099.43183984,"stats":{"moe":1.4639999036808505e-10,"rme":0.39248518985983866,"sem":7.469387263677809e-11,"deviation":5.928642343717415e-10,"mean":3.7300768067290974e-8,"variance":3.514880003971913e-19,"numSamples":63},"times":{"cycle":0.07739454304592457,"elapsed":5.97,"period":3.7300768067290974e-8,"timeStamp":1737577618111}},"platforms":{"Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0":{"aborted":false,"count":4122876,"cycles":6,"hz":52010686.277354434,"stats":{"moe":2.6654535438973097e-10,"rme":1.3863206805850556,"sem":1.3599252774986275e-10,"deviation":1.0964068105620363e-9,"mean":1.922681801711588e-8,"variance":1.2021078942468169e-18,"numSamples":65},"times":{"cycle":0.07926978655913465,"elapsed":6.235,"period":1.922681801711588e-8,"timeStamp":1737558671084}},"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36":{"aborted":false,"count":11544413,"cycles":10,"hz":149434241.06224847,"stats":{"moe":4.042305384409091e-11,"rme":0.6040588372610131,"sem":2.062400706331169e-11,"deviation":1.6881477338279532e-10,"mean":6.691906706866729e-9,"variance":2.8498427712284537e-20,"numSamples":67},"times":{"cycle":0.07725413478153945,"elapsed":6.169,"period":6.691906706866729e-9,"timeStamp":1737558750041}},"Mozilla/5.0 (Android 11; Mobile; rv:134.0) Gecko/134.0 Firefox/134.0":{"aborted":false,"count":2074878,"cycles":7,"hz":26809099.43183984,"stats":{"moe":1.4639999036808505e-10,"rme":0.39248518985983866,"sem":7.469387263677809e-11,"deviation":5.928642343717415e-10,"mean":3.7300768067290974e-8,"variance":3.514880003971913e-19,"numSamples":63},"times":{"cycle":0.07739454304592457,"elapsed":5.97,"period":3.7300768067290974e-8,"timeStamp":1737577618111}}}},{"name":"Class based, while(!res.done) loop","code":"const iter = i_class;\nlet res = iter.next();\nwhile(!res.done) {\n ret = res.value;\n res = iter.next();\n}\n","results":{"aborted":false,"count":2108585,"cycles":7,"hz":27710579.46552573,"stats":{"moe":1.1126078651510699e-10,"rme":0.30831008661237663,"sem":5.676570740566683e-11,"deviation":4.5765976436898577e-10,"mean":3.608730020402797e-8,"variance":2.094524599222756e-19,"numSamples":65},"times":{"cycle":0.07609313990071032,"elapsed":6.043,"period":3.608730020402797e-8,"timeStamp":1737577624123}},"platforms":{"Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0":{"aborted":false,"count":4866187,"cycles":6,"hz":60974520.95100542,"stats":{"moe":1.8548312163643879e-10,"rme":1.1309744486278923,"sem":9.463424573287693e-11,"deviation":7.391170870648727e-10,"mean":1.6400292850246833e-8,"variance":5.462940683912627e-19,"numSamples":61},"times":{"cycle":0.07980689186406409,"elapsed":5.979,"period":1.6400292850246833e-8,"timeStamp":1737558677327}},"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36":{"aborted":false,"count":10889992,"cycles":11,"hz":140132476.50614145,"stats":{"moe":1.727686486502378e-11,"rme":0.24210498597977254,"sem":8.814726971950908e-12,"deviation":7.161118044650963e-11,"mean":7.136104527176996e-9,"variance":5.128161164942564e-21,"numSamples":66},"times":{"cycle":0.07771212121212127,"elapsed":6.152,"period":7.136104527176996e-9,"timeStamp":1737558756215}},"Mozilla/5.0 (Android 11; Mobile; rv:134.0) Gecko/134.0 Firefox/134.0":{"aborted":false,"count":2108585,"cycles":7,"hz":27710579.46552573,"stats":{"moe":1.1126078651510699e-10,"rme":0.30831008661237663,"sem":5.676570740566683e-11,"deviation":4.5765976436898577e-10,"mean":3.608730020402797e-8,"variance":2.094524599222756e-19,"numSamples":65},"times":{"cycle":0.07609313990071032,"elapsed":6.043,"period":3.608730020402797e-8,"timeStamp":1737577624123}}}},{"name":"Class based, return self, for..of loop","code":"for (const k of i_rs) {\n ret = k;\n}\n","results":{"aborted":false,"count":2675193,"cycles":7,"hz":33084077.420308437,"stats":{"moe":1.8672040318257426e-9,"rme":6.177472274843493,"sem":9.526551182784401e-10,"deviation":7.4404743287850025e-9,"mean":3.022602042957851e-8,"variance":5.536065823730863e-17,"numSamples":61},"times":{"cycle":0.08086043827106543,"elapsed":7.259,"period":3.022602042957851e-8,"timeStamp":1737577630199}},"platforms":{"Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0":{"aborted":false,"count":6014308,"cycles":8,"hz":75517544.06148133,"stats":{"moe":1.8122886214914124e-10,"rme":1.3685958582559898,"sem":9.246370517813329e-11,"deviation":7.22164623400644e-10,"mean":1.3241956057070221e-8,"variance":5.215217432913938e-19,"numSamples":61},"times":{"cycle":0.07964120224968589,"elapsed":6.064,"period":1.3241956057070221e-8,"timeStamp":1737558683312}},"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36":{"aborted":false,"count":13087161,"cycles":7,"hz":163952972.0139515,"stats":{"moe":7.84537808189865e-11,"rme":1.2862730531003979,"sem":4.0027439193360465e-11,"deviation":3.202195135468837e-10,"mean":6.099309989421268e-9,"variance":1.0254053685620285e-19,"numSamples":64},"times":{"cycle":0.07982265182046444,"elapsed":6.032,"period":6.099309989421268e-9,"timeStamp":1737558762372}},"Mozilla/5.0 (Android 11; Mobile; rv:134.0) Gecko/134.0 Firefox/134.0":{"aborted":false,"count":2675193,"cycles":7,"hz":33084077.420308437,"stats":{"moe":1.8672040318257426e-9,"rme":6.177472274843493,"sem":9.526551182784401e-10,"deviation":7.4404743287850025e-9,"mean":3.022602042957851e-8,"variance":5.536065823730863e-17,"numSamples":61},"times":{"cycle":0.08086043827106543,"elapsed":7.259,"period":3.022602042957851e-8,"timeStamp":1737577630199}}}},{"name":"Class based, return self, while(!res.done) loop","code":"const iter = i_rs;\nlet res = iter.next();\nwhile(!res.done) {\n ret = res.value;\n res = iter.next();\n}","results":{"aborted":false,"count":3106733,"cycles":6,"hz":38335445.339358136,"stats":{"moe":2.4446879329684044e-10,"rme":0.937182006260987,"sem":1.2472897617185737e-10,"deviation":9.741644457224177e-10,"mean":2.608551931894013e-8,"variance":9.489963673096652e-19,"numSamples":61},"times":{"cycle":0.08104074369028882,"elapsed":6.304,"period":2.608551931894013e-8,"timeStamp":1737577637510}},"platforms":{"Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0":{"aborted":false,"count":7685203,"cycles":6,"hz":93903776.77198686,"stats":{"moe":1.761813925669777e-10,"rme":1.6544098158987262,"sem":8.988846559539678e-11,"deviation":7.077824858809941e-10,"mean":1.0649198939337203e-8,"variance":5.009560473198796e-19,"numSamples":62},"times":{"cycle":0.08184125563619109,"elapsed":5.994,"period":1.0649198939337203e-8,"timeStamp":1737558689381}},"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36":{"aborted":false,"count":13015516,"cycles":7,"hz":165665025.90051332,"stats":{"moe":7.538657968084287e-11,"rme":1.2488919675377945,"sem":3.846254065349126e-11,"deviation":3.0528695208254884e-10,"mean":6.036277087238251e-9,"variance":9.320012311185248e-20,"numSamples":63},"times":{"cycle":0.07856526100938285,"elapsed":5.85,"period":6.036277087238251e-9,"timeStamp":1737558768409}},"Mozilla/5.0 (Android 11; Mobile; rv:134.0) Gecko/134.0 Firefox/134.0":{"aborted":false,"count":3106733,"cycles":6,"hz":38335445.339358136,"stats":{"moe":2.4446879329684044e-10,"rme":0.937182006260987,"sem":1.2472897617185737e-10,"deviation":9.741644457224177e-10,"mean":2.608551931894013e-8,"variance":9.489963673096652e-19,"numSamples":61},"times":{"cycle":0.08104074369028882,"elapsed":6.304,"period":2.608551931894013e-8,"timeStamp":1737577637510}}}},{"name":"Class based, not iterable","code":"const iter = i_ni;\nwhile(!iter.done) {\n ret = iter.next();\n}","results":{"aborted":false,"count":7112564,"cycles":7,"hz":92234354.01694797,"stats":{"moe":2.8921515856020637e-11,"rme":0.2667557332170981,"sem":1.4755875436745224e-11,"deviation":1.180470034939618e-10,"mean":1.084194724035527e-8,"variance":1.3935095033903428e-20,"numSamples":64},"times":{"cycle":0.07711404363165024,"elapsed":6.166,"period":1.084194724035527e-8,"timeStamp":1737577643904}},"platforms":{"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36":{"aborted":false,"count":13518739,"cycles":7,"hz":174166868.45133427,"stats":{"moe":3.4169145750665243e-11,"rme":0.595113311305058,"sem":1.743323762789043e-11,"deviation":1.4162829200612657e-10,"mean":5.741620142176583e-9,"variance":2.0058573096572658e-20,"numSamples":66},"times":{"cycle":0.07761946413922811,"elapsed":5.993,"period":5.741620142176583e-9,"timeStamp":1737558774264}},"Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0":{"aborted":false,"count":17271724,"cycles":7,"hz":218337545.32370156,"stats":{"moe":2.6557647265167233e-11,"rme":0.579853151344933,"sem":1.3549820033248588e-11,"deviation":1.083985602659887e-10,"mean":4.580064315175047e-9,"variance":1.1750247867739186e-20,"numSamples":64},"times":{"cycle":0.07910560675395242,"elapsed":6.048,"period":4.580064315175047e-9,"timeStamp":1737558695380}},"Mozilla/5.0 (Android 11; Mobile; rv:134.0) Gecko/134.0 Firefox/134.0":{"aborted":false,"count":7112564,"cycles":7,"hz":92234354.01694797,"stats":{"moe":2.8921515856020637e-11,"rme":0.2667557332170981,"sem":1.4755875436745224e-11,"deviation":1.180470034939618e-10,"mean":1.084194724035527e-8,"variance":1.3935095033903428e-20,"numSamples":64},"times":{"cycle":0.07711404363165024,"elapsed":6.166,"period":1.084194724035527e-8,"timeStamp":1737577643904}}}},{"name":"Class based, not iterable v2 (minifies slightly better)","code":"const iter = i_ni2;\nwhile(iter.state) {\n ret = iter.next();\n}","results":{"aborted":false,"count":7032502,"cycles":6,"hz":92177132.72507119,"stats":{"moe":3.707769737659879e-11,"rme":0.3417715832222771,"sem":1.8917192539081013e-11,"deviation":1.525152821242614e-10,"mean":1.0848677653953654e-8,"variance":2.326091128144305e-20,"numSamples":65},"times":{"cycle":0.07629334729878438,"elapsed":6.04,"period":1.0848677653953654e-8,"timeStamp":1737577650149}},"platforms":{"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36":{"aborted":false,"count":13714221,"cycles":7,"hz":179378299.5906231,"stats":{"moe":2.495458705667736e-11,"rme":0.4476311393212957,"sem":1.2731932171774163e-11,"deviation":1.0499020232484906e-10,"mean":5.574810343738337e-9,"variance":1.102294258421274e-20,"numSamples":68},"times":{"cycle":0.07645418108711352,"elapsed":6.012,"period":5.574810343738337e-9,"timeStamp":1737558780262}},"Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0":{"aborted":false,"count":16696007,"cycles":5,"hz":214695198.2509162,"stats":{"moe":5.6843916917420104e-11,"rme":1.220411601194412,"sem":2.9001998427255155e-11,"deviation":2.3019622608721058e-10,"mean":4.6577660243304135e-9,"variance":5.299030250479416e-20,"numSamples":63},"times":{"cycle":0.07776609414658275,"elapsed":5.737,"period":4.6577660243304135e-9,"timeStamp":1737558701433}},"Mozilla/5.0 (Android 11; Mobile; rv:134.0) Gecko/134.0 Firefox/134.0":{"aborted":false,"count":7032502,"cycles":6,"hz":92177132.72507119,"stats":{"moe":3.707769737659879e-11,"rme":0.3417715832222771,"sem":1.8917192539081013e-11,"deviation":1.525152821242614e-10,"mean":1.0848677653953654e-8,"variance":2.326091128144305e-20,"numSamples":65},"times":{"cycle":0.07629334729878438,"elapsed":6.04,"period":1.0848677653953654e-8,"timeStamp":1737577650149}}}}]} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment