The fix is in JDK 9 now. I will propose this to be backported this to 8u, which means it should appear in some 8u release soon, but I can’t make any promise about a specific release or date.
Hannes > Am 09.01.2017 um 23:44 schrieb Jesus Luzon <jlu...@riotgames.com>: > > Hey folks, > > Looked at the ticket and noticed it has been marked as fixed. woot! Thank you > so much! > > My team has been asking me if I can find out the date this fix will get > released. I noticed the version on there (version 9) states it has no release > date yet. Is there any tentative date you all have for the net release this > would be included in? Even a ballpark figure would be awesome. > > Thanks. > > On Fri, Dec 9, 2016 at 2:49 AM, Jesus Luzon <jlu...@riotgames.com> wrote: > Wow I totally missed the var. Thanks for that! I actually had changed our > code to use ThreadLocal ScriptObjectMirrors created from the CompiledScript > with the following code: > > ScriptObjectMirror mirror = mirrorThreadLocal.get(); > if (mirror == null) { > Bindings bindings = compiledScript.getEngine().createBindings(); > compiledScript.eval(bindings); > mirror = (ScriptObjectMirror) bindings.get("transform"); > mirrorThreadLocal.set(mirror); > } > return (String) mirror.call(null, something); > > Given that we will always run standalone functions to filter data, is there > one we should be using over the other? > > Lastly thanks for filing the bug. I'll keep track of it so I can make sure to > upgrade when a fix comes out. > > On Fri, Dec 9, 2016 at 2:37 AM, Hannes Wallnöfer > <hannes.wallnoe...@oracle.com> wrote: > Jesus, > > I looked at this issue more in depth and there are two problems here, one on > your side and one on ours: > > The problem with your code is that you left out the „var“ declaration of the > „response“ variable in the third line of your function. This means that > „response“ is allocated as a global variable outside the scope of the > function. When you run this in parallel with multiple threads you actually > access the same object from multiple threads, meaning your output will be > corrupt. > > Because of things like this, it is actually a good idea to run JavaScript in > strict mode (e.g. by using „use strict“ directive in your JavaScript code, or > by creating the engine with -strict option). Another solution would be to use > multiple engines or bindings, which should not have a big performance impact > once the other problem is fixed. > > Which leads us to the problem on our side, which is performance of sparse > arrays. As you have noticed, using something that is not a valid array index > greatly improves performance, and that is because some array element > assignment are implemented very inefficiently in Nashorn. I’ve filed a bug > for this: > > https://bugs.openjdk.java.net/browse/JDK-8170977 > > Once this bug is fixed, using numeric keys should be roughly as fast as using > non-numeric ones. > > Hannes > > > > Am 09.12.2016 um 04:47 schrieb Jesus Luzon <jlu...@riotgames.com>: > > > > I came up with a workaround which is getting us through this but it > > definitely seems like this is a bug. The gist is I append an arbitrary > > string (we made it complex on our end to make it unlikely something else > > has this string inside) to the key and then remove all instances of said > > string on the JSON String resulting from calling stringify. We are leaving > > this for overnight testing but it showed promising results immediately. > > > > String script = "function transform(input) {" + > > "var result = JSON.parse(input);" + > > "response = {};\n" + > > "for (var i = 0; i < result.length; i++) {\n" + > > " var summoner = {};\n" + > > " summoner.id = result[i].id;\n" + > > " summoner.name = result[i].name;\n" + > > " summoner.profileIconId = result[i].profileIconId;\n" + > > " summoner.revisionDate = result[i].revisionDate;\n" + > > " summoner.summonerLevel = result[i].level;\n" + > > " response[\"someArbitraryString\" + summoner.id] = > > summoner;\n" + > > "}\n" + > > "var stringy = JSON.stringify(response);" + > > "result = stringy.replace(/someArbitraryString/g, \"\");" + > > "return result;" + > > "};"; > > > > On Thu, Dec 8, 2016 at 4:54 PM, Jesus Luzon <jlu...@riotgames.com> wrote: > > It doesn't seem like changing to a string fixed it. We dug deeper and found > > a very interesting issue though. After running the invocable a few thousand > > times, when we put a breakpoint in ArrayData.computerIteratorKeys() and we > > found that it would stop at an execution from SparseArrayData with an > > underlying array of size 923392, stored length of 461672 (this is one of > > our IDs, the largest 6 digit one). Because of this we tried a run changing > > all the IDs in the array we pass in to number from 1-38 and this thing went > > blazing fast. When putting a break point in the same place, this array in > > SpareArrayData was now of size 39. We then changed an id in the array we > > take in to be 1337 and the size of the array in the SparseArrayData was > > 1338. > > > > I don't understand why or how to prevent but it's using this ID as an index > > for SpareArrayData underlying array. If someone can help me find a > > workaround for this I would be extremely grateful. > > > > On Thu, Dec 8, 2016 at 3:52 AM, Hannes Wallnöfer > > <hannes.wallnoe...@oracle.com> wrote: > > Yes, this is very likely to be the cause of the problem. However, I do > > think we should be able to handle sparse array data better, so it’s quite > > possible that you exposed some weak spot in our implementation. I’ll have a > > look into what’s going on. > > > > Hannes > > > > > > > Am 08.12.2016 um 00:40 schrieb Jesus Luzon <jlu...@riotgames.com>: > > > > > > Looks like the memory leak is due to the way we wrote our code and how > > > javascript works. I was expecting the line response[summoner.id] = > > > summoner; to build a map but it turns out that if you use a number as the > > > "key", javscript automatically fills the indexes in the middle with null > > > (Undefined type?). When these IDs are very large, it is creating huge > > > arrays that take longer to garbage collect than the code executing. I am > > > about to start testing this on our end to make sure we see the > > > improvements we expect. > > > > > > Does this idea seem like it is reasonably possible? > > > > > > On Wed, Dec 7, 2016 at 11:23 AM, Jesus Luzon <jlu...@riotgames.com> wrote: > > > Yes, it's an array of objects which I'll paste. And yes, I'm just calling > > > invokeFunction from many many different threads. I'm also going to go > > > back and take a look at all the heap dumps we have to re-confirm what I > > > mentioned. > > > > > > "[\n" + > > > " {\n" + > > > " \"id\": 6011511,\n" + > > > " \"accountId\": 203192481,\n" + > > > " \"name\": \"Adam Pro Qardaş\",\n" + > > > " \"profileIconId\": 25,\n" + > > > " \"level\": 5,\n" + > > > " \"expPoints\": 83,\n" + > > > " \"infPoints\": 1475,\n" + > > > " \"revisionDate\": 1406631727000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 2810674,\n" + > > > " \"accountId\": 200706913,\n" + > > > " \"name\": \"ABZ Devrim\",\n" + > > > " \"profileIconId\": 663,\n" + > > > " \"level\": 13,\n" + > > > " \"expPoints\": 982,\n" + > > > " \"infPoints\": 10472,\n" + > > > " \"revisionDate\": 1450791227000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 5411195,\n" + > > > " \"accountId\": 202647689,\n" + > > > " \"name\": \"Ace HypcronN\",\n" + > > > " \"profileIconId\": 911,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 73,\n" + > > > " \"infPoints\": 182445,\n" + > > > " \"revisionDate\": 1480781650000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 1363020,\n" + > > > " \"accountId\": 1357837,\n" + > > > " \"name\": \"AdanaLee\",\n" + > > > " \"profileIconId\": 502,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 125,\n" + > > > " \"infPoints\": 719299,\n" + > > > " \"revisionDate\": 1480530778000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 8261198,\n" + > > > " \"accountId\": 205027096,\n" + > > > " \"name\": \"Achilehuz\",\n" + > > > " \"profileIconId\": 1381,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 10,\n" + > > > " \"infPoints\": 158603,\n" + > > > " \"revisionDate\": 1480770307000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 12685857,\n" + > > > " \"accountId\": 207591166,\n" + > > > " \"name\": \"acımasızpicc\",\n" + > > > " \"profileIconId\": 9,\n" + > > > " \"level\": 21,\n" + > > > " \"expPoints\": 840,\n" + > > > " \"infPoints\": 16659,\n" + > > > " \"revisionDate\": 1480515325000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 10860127,\n" + > > > " \"accountId\": 206507727,\n" + > > > " \"name\": \"AAngelFlyy\",\n" + > > > " \"profileIconId\": 1395,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 10,\n" + > > > " \"infPoints\": 73111,\n" + > > > " \"revisionDate\": 1480787870000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 3292376,\n" + > > > " \"accountId\": 201048714,\n" + > > > " \"name\": \"ACAB1907\",\n" + > > > " \"profileIconId\": 20,\n" + > > > " \"level\": 6,\n" + > > > " \"expPoints\": 305,\n" + > > > " \"infPoints\": 2107,\n" + > > > " \"revisionDate\": 1402448089000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 461671,\n" + > > > " \"accountId\": 446571,\n" + > > > " \"name\": \"Acta Est Fabulâ\",\n" + > > > " \"profileIconId\": 1435,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 47,\n" + > > > " \"infPoints\": 644672,\n" + > > > " \"revisionDate\": 1480626505000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 394183,\n" + > > > " \"accountId\": 379083,\n" + > > > " \"name\": \"acekse4\",\n" + > > > " \"profileIconId\": 27,\n" + > > > " \"level\": 5,\n" + > > > " \"expPoints\": 223,\n" + > > > " \"infPoints\": 908,\n" + > > > " \"revisionDate\": 1348116544000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 5941247,\n" + > > > " \"accountId\": 203106300,\n" + > > > " \"name\": \"abdul7878\",\n" + > > > " \"profileIconId\": 26,\n" + > > > " \"level\": 3,\n" + > > > " \"expPoints\": 10,\n" + > > > " \"infPoints\": 401,\n" + > > > " \"revisionDate\": 1406029148000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 2467446,\n" + > > > " \"accountId\": 200459837,\n" + > > > " \"name\": \"ActionC\",\n" + > > > " \"profileIconId\": 986,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 74,\n" + > > > " \"infPoints\": 401367,\n" + > > > " \"revisionDate\": 1480808608000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 9402979,\n" + > > > " \"accountId\": 205698832,\n" + > > > " \"name\": \"Ablenia \",\n" + > > > " \"profileIconId\": 1129,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 19,\n" + > > > " \"infPoints\": 163518,\n" + > > > " \"revisionDate\": 1480687603000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 13187505,\n" + > > > " \"accountId\": 207898213,\n" + > > > " \"name\": \"aDaMiYiM\",\n" + > > > " \"profileIconId\": 1301,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 116,\n" + > > > " \"infPoints\": 45214,\n" + > > > " \"revisionDate\": 1480793258000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 4141059,\n" + > > > " \"accountId\": 201688290,\n" + > > > " \"name\": \"AbiminÇarı\",\n" + > > > " \"profileIconId\": 898,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 152,\n" + > > > " \"infPoints\": 752477,\n" + > > > " \"revisionDate\": 1480635961000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 5702134,\n" + > > > " \"accountId\": 202899395,\n" + > > > " \"name\": \"Above the Clouds\",\n" + > > > " \"profileIconId\": 684,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 110,\n" + > > > " \"infPoints\": 288096,\n" + > > > " \"revisionDate\": 1471011372000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 5810740,\n" + > > > " \"accountId\": 202985228,\n" + > > > " \"name\": \"aBimm\",\n" + > > > " \"profileIconId\": 11,\n" + > > > " \"level\": 13,\n" + > > > " \"expPoints\": 1180,\n" + > > > " \"infPoints\": 10736,\n" + > > > " \"revisionDate\": 1409832684000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 5817751,\n" + > > > " \"accountId\": 203050678,\n" + > > > " \"name\": \"AD Glorıam\",\n" + > > > " \"profileIconId\": 982,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 111,\n" + > > > " \"infPoints\": 304658,\n" + > > > " \"revisionDate\": 1480795250000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 9851802,\n" + > > > " \"accountId\": 206011054,\n" + > > > " \"name\": \"AdarAllame\",\n" + > > > " \"profileIconId\": 911,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 48,\n" + > > > " \"infPoints\": 73763,\n" + > > > " \"revisionDate\": 1479422812000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 12735622,\n" + > > > " \"accountId\": 207587019,\n" + > > > " \"name\": \"absinthe666\",\n" + > > > " \"profileIconId\": 903,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 83,\n" + > > > " \"infPoints\": 40302,\n" + > > > " \"revisionDate\": 1480782923000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 6371389,\n" + > > > " \"accountId\": 203416952,\n" + > > > " \"name\": \"adamsatıcı\",\n" + > > > " \"profileIconId\": 3,\n" + > > > " \"level\": 4,\n" + > > > " \"expPoints\": 17,\n" + > > > " \"infPoints\": 685,\n" + > > > " \"revisionDate\": 1409320171000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 7828139,\n" + > > > " \"accountId\": 204927980,\n" + > > > " \"name\": \"AbsoluteForce\",\n" + > > > " \"profileIconId\": 950,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 139,\n" + > > > " \"infPoints\": 208789,\n" + > > > " \"revisionDate\": 1480804396000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 1373229,\n" + > > > " \"accountId\": 1358441,\n" + > > > " \"name\": \"AbsoluteDeath\",\n" + > > > " \"profileIconId\": 7,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 34,\n" + > > > " \"infPoints\": 223655,\n" + > > > " \"revisionDate\": 1471867646000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 7694972,\n" + > > > " \"accountId\": 204803668,\n" + > > > " \"name\": \"ac pnp\",\n" + > > > " \"profileIconId\": 937,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 161,\n" + > > > " \"infPoints\": 249681,\n" + > > > " \"revisionDate\": 1480801507000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 1373524,\n" + > > > " \"accountId\": 1350474,\n" + > > > " \"name\": \"Abdüü\",\n" + > > > " \"profileIconId\": 1301,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 103,\n" + > > > " \"infPoints\": 286803,\n" + > > > " \"revisionDate\": 1476621827000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 1650227,\n" + > > > " \"accountId\": 200000503,\n" + > > > " \"name\": \"AD Ambrosia\",\n" + > > > " \"profileIconId\": 1152,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 139,\n" + > > > " \"infPoints\": 156333,\n" + > > > " \"revisionDate\": 1480805320000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 8331358,\n" + > > > " \"accountId\": 205073925,\n" + > > > " \"name\": \"acarmanyust2\",\n" + > > > " \"profileIconId\": 0,\n" + > > > " \"level\": 2,\n" + > > > " \"expPoints\": 43,\n" + > > > " \"infPoints\": 318,\n" + > > > " \"revisionDate\": 1423915139000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 1862106,\n" + > > > " \"accountId\": 200139838,\n" + > > > " \"name\": \"aboU\",\n" + > > > " \"profileIconId\": 1155,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 0,\n" + > > > " \"infPoints\": 412616,\n" + > > > " \"revisionDate\": 1480771055000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 2362628,\n" + > > > " \"accountId\": 685649,\n" + > > > " \"name\": \"AcıFısTık\",\n" + > > > " \"profileIconId\": 1074,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 48,\n" + > > > " \"infPoints\": 233882,\n" + > > > " \"revisionDate\": 1480786233000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 4323909,\n" + > > > " \"accountId\": 201917672,\n" + > > > " \"name\": \"Addrenalin\",\n" + > > > " \"profileIconId\": 603,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 55,\n" + > > > " \"infPoints\": 220605,\n" + > > > " \"revisionDate\": 1432647338000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 377206,\n" + > > > " \"accountId\": 362106,\n" + > > > " \"name\": \"Aburame Shino\",\n" + > > > " \"profileIconId\": 844,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 84,\n" + > > > " \"infPoints\": 354087,\n" + > > > " \"revisionDate\": 1477666556000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 5377433,\n" + > > > " \"accountId\": 202697921,\n" + > > > " \"name\": \"AcEcolton35\",\n" + > > > " \"profileIconId\": 984,\n" + > > > " \"level\": 25,\n" + > > > " \"expPoints\": 751,\n" + > > > " \"infPoints\": 30061,\n" + > > > " \"revisionDate\": 1475503024000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 2381404,\n" + > > > " \"accountId\": 200333680,\n" + > > > " \"name\": \"adafakaaa\",\n" + > > > " \"profileIconId\": 663,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 8,\n" + > > > " \"infPoints\": 534204,\n" + > > > " \"revisionDate\": 1480719827000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 1281203,\n" + > > > " \"accountId\": 1259342,\n" + > > > " \"name\": \"AC Klondike\",\n" + > > > " \"profileIconId\": 898,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 27,\n" + > > > " \"infPoints\": 191429,\n" + > > > " \"revisionDate\": 1480294973000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 13161471,\n" + > > > " \"accountId\": 207847181,\n" + > > > " \"name\": \"adar21\",\n" + > > > " \"profileIconId\": 26,\n" + > > > " \"level\": 10,\n" + > > > " \"expPoints\": 143,\n" + > > > " \"infPoints\": 3558,\n" + > > > " \"revisionDate\": 1476529855000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 5841915,\n" + > > > " \"accountId\": 202998794,\n" + > > > " \"name\": \"Achilles29\",\n" + > > > " \"profileIconId\": 666,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 41,\n" + > > > " \"infPoints\": 219714,\n" + > > > " \"revisionDate\": 1480777744000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 2853062,\n" + > > > " \"accountId\": 200726707,\n" + > > > " \"name\": \"AbIanStarBebegim\",\n" + > > > " \"profileIconId\": 909,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 64,\n" + > > > " \"infPoints\": 297580,\n" + > > > " \"revisionDate\": 1480556859000\n" + > > > " },\n" + > > > " {\n" + > > > " \"id\": 8323114,\n" + > > > " \"accountId\": 205093515,\n" + > > > " \"name\": \"Absuruk\",\n" + > > > " \"profileIconId\": 6,\n" + > > > " \"level\": 30,\n" + > > > " \"expPoints\": 21,\n" + > > > " \"infPoints\": 121086,\n" + > > > " \"revisionDate\": 1480820801000\n" + > > > " }\n" + > > > "]" > > > > > > On Wed, Dec 7, 2016 at 7:01 AM, Hannes Wallnöfer > > > <hannes.wallnoe...@oracle.com> wrote: > > > Hi Jesus, > > > > > > I’m trying to reproduce the problem, and just want to make sure I get the > > > missing pieces right. > > > > > > You already showed us how you’re setting up the engine and the JS code > > > you’re running. I assume the JSON code you’re parsing is a simple array > > > of objects? And you’re just calling Invocable.invokeFunction on the > > > ScriptEngine from multiple threads in parallel, right? > > > > > > Thanks, > > > Hannes > > > > > > > > > > Am 07.12.2016 um 00:03 schrieb Jesus Luzon <jlu...@riotgames.com>: > > > > > > > > When we share one invocable across many threads and run invokeFunction > > > > it > > > > happens, such as this: > > > > > > > > ExecutorService executor = Executors.newFixedThreadPool(50); > > > >> > > > >> Invocable invocable = generateInvocable(script); > > > >> > > > >> AtomicLong count = new AtomicLong(); > > > >> > > > >> for (int i = 0; i < 50; i++) { > > > >> > > > >> executor.submit(new Runnable() { > > > >> > > > >> @Override > > > >> > > > >> public void run() { > > > >> > > > >> try { > > > >> > > > >> while(true) { > > > >> > > > >> invocable.invokeFunction("transform", > > > >>> something); > > > >> > > > >> count.incrementAndGet(); > > > >> > > > >> } > > > >> > > > >> } catch (NoSuchMethodException | ScriptException > > > >>> e) { > > > >> > > > >> e.printStackTrace(); > > > >> > > > >> } > > > >> > > > >> } > > > >> > > > >> }); > > > >> > > > >> } > > > >> > > > >> > > > > > > > > > > > > On Tue, Dec 6, 2016 at 2:59 PM, Jim Laskey (Oracle) > > > > <james.las...@oracle.com > > > >> wrote: > > > > > > > >> Intersting. The example you posted demonstrates this behaviour? If so > > > >> I’ll file a bug and dig in. It sounds like an object is being reused > > > >> across invocations and accumulating changes to the property map. > > > >> > > > >> — Jim > > > >> > > > >> > > > >> On Dec 6, 2016, at 5:12 PM, Jesus Luzon <jlu...@riotgames.com> wrote: > > > >> > > > >> With more threads you are impacting the same 8 cores, so it will taper > > > >> off > > > >>> after 8 threads. If it’s a 2x4 core machine then I can see 4 being a > > > >>> threshold depending on System performance. Transport: I meant if you > > > >>> were > > > >>> using sockets to provide the script. > > > >> > > > >> This makes sense. This one's on me then. > > > >> > > > >> > > > >>> So you are using the same invocable instance for all threads? If so, > > > >>> then you are probably good to go. As far as leaks are concerned, not > > > >>> sure > > > >>> how you would get leaks from Nashorn. The JSON object is written in > > > >>> Java, > > > >>> and little JavaScript involved. > > > >> > > > >> > > > >> > > > >>> In your example, pull up Invocable invocable = > > > >>> generateInvocable(script); > > > >>> out of the loop and use the same invocable for all threads. > > > >> > > > >> > > > >> We were using one invocable across all threads and we were getting > > > >> slowdowns on execution, high CPU Usage and memory leaks that led to > > > >> OutOfMemory errors. I could trace the leak to > > > >> > > > >> jdk.nashorn.internal.objects.Global -> *objectSpill* Object[8] -> > > > >> jdk.nashorn.internal.scripts.JO4 -> *arrayData* > > > >> jdk.nashorn.internal.runtime.arrays.SparseArraysData -> *underlying* > > > >> jdk.nashorn.internal.runtime.arrays.DeletedArrayFilter > > > >> > > > >> which just keeps growing forever. > > > >> > > > >> On Tue, Dec 6, 2016 at 6:30 AM, Jim Laskey (Oracle) < > > > >> james.las...@oracle.com> wrote: > > > >> > > > >>> > > > >>> On Dec 6, 2016, at 9:56 AM, Jesus Luzon <jlu...@riotgames.com> wrote: > > > >>> > > > >>> The cost of creating a new engine is significant. So share an engine > > > >>>> across threads but use *eval > > > >>>> <https://docs.oracle.com/javase/7/docs/api/javax/script/ScriptEngine.html#eval(java.lang.String,%20javax.script.ScriptContext)>* > > > >>>> (String > > > >>>> <https://docs.oracle.com/javase/7/docs/api/java/lang/String.html> > > > >>>> script, ScriptContext > > > >>>> <https://docs.oracle.com/javase/7/docs/api/javax/script/ScriptContext.html> > > > >>>> context) instead, separate context per execution. If your JavaScript > > > >>>> code does not modify globals you can get away with using the same > > > >>>> engine, > > > >>>> same compiled script on each thread. > > > >>> > > > >>> > > > >>> I guess there's a few things here I don't understand. One thing I'm > > > >>> trying to do is sharing a CompiledScript (which is why I'm using > > > >>> invocable). Also, what exactly does modify globals mean? All our > > > >>> filters do > > > >>> the same thing, make a function that takes a JSON String, turns it > > > >>> into a > > > >>> JSON, modifies it and then stringifies it back. No state is changed of > > > >>> anything else but there are temporary vars created inside the scope > > > >>> of the > > > >>> function. When we run this multithreaded, running invokeFunction > > > >>> slows down > > > >>> significantly and we get crazy memory leaks. > > > >>> > > > >>> > > > >>> So you are using the same invocable instance for all threads? If so, > > > >>> then you are probably good to go. As far as leaks are concerned, not > > > >>> sure > > > >>> how you would get leaks from Nashorn. The JSON object is written in > > > >>> Java, > > > >>> and little JavaScript involved. > > > >>> > > > >>> > > > >>> Of course there are many factors involved n performance. How many > > > >>> cores > > > >>>> do you have on the test machine? How much memory in the process? > > > >>>> What > > > >>>> transport are you using between threads? That sort of thing. Other > > > >>>> than > > > >>>> constructing then engine and context Nashorn performance should > > > >>>> scale. > > > >>> > > > >>> I'm using an 8 core machine to test with 2.5Gs of RAM allocated to the > > > >>> process. Not sure what transports between threads means, but this is > > > >>> the > > > >>> code I'm benchmarking with. Increasing the number of threads actually > > > >>> makes > > > >>> it go faster until about 4 threads, then adding more threads takes > > > >>> the same > > > >>> amount to get to 1000 and and after a certain point it is just slower > > > >>> to > > > >>> get to 1000 counts. Some of our filters need to be able to run over > > > >>> 1000 > > > >>> times a second (across all threads) and the fastest time I could > > > >>> actually > > > >>> get with this was about 2.4 seconds for a 1000 counts. > > > >>> > > > >>>> ExecutorService executor = Executors.newFixedThreadPool(50); > > > >>>> > > > >>>> AtomicLong count = new AtomicLong(); > > > >>>> > > > >>>> for (int i = 0; i < 50; i++) { > > > >>>> > > > >>>> executor.submit(new Runnable() { > > > >>>> > > > >>>> @Override > > > >>>> > > > >>>> public void run() { > > > >>>> > > > >>>> > > > >>>>> try { > > > >>>> > > > >>>> Invocable invocable = > > > >>>>> generateInvocable(script); > > > >>>> > > > >>>> while(true) { > > > >>>> > > > >>>> invocable.invokeFunction("transform", > > > >>>>> something); > > > >>>> > > > >>>> count.incrementAndGet(); > > > >>>> > > > >>>> } > > > >>>> > > > >>>> } catch (NoSuchMethodException | > > > >>>> ScriptException > > > >>>>> e) { > > > >>>> > > > >>>> e.printStackTrace(); > > > >>>> > > > >>>> } > > > >>>> > > > >>>> } > > > >>>> > > > >>>> }); > > > >>>> > > > >>>> } > > > >>>> > > > >>>> long lastTimestamp = System.currentTimeMillis(); > > > >>>> > > > >>>> while(true) { > > > >>>> > > > >>>> > > > >>>>> if (count.get() > 1000) { > > > >>>> > > > >>>> count.getAndAdd(-1000); > > > >>>> > > > >>>> System.out.println((System.currentTimeMillis() - > > > >>>>> lastTimestamp)/1000.0); > > > >>>> > > > >>>> lastTimestamp = System.currentTimeMillis(); > > > >>>> > > > >>>> } > > > >>>> > > > >>>> } > > > >>>> > > > >>>> > > > >>> With more threads you are impacting the same 8 cores, so it will taper > > > >>> off after 8 threads. If it’s a 2x4 core machine then I can see 4 > > > >>> being a > > > >>> threshold depending on System performance. Transport: I meant if you > > > >>> were > > > >>> using sockets to provide the script. > > > >>> > > > >>> In your example, pull up Invocable invocable = > > > >>> generateInvocable(script); > > > >>> out of the loop and use the same invocable for all threads. > > > >>> > > > >>> - Jim > > > >>> > > > >>> > > > >>> > > > >>> > > > >>> On Tue, Dec 6, 2016 at 5:31 AM, Jim Laskey (Oracle) < > > > >>> james.las...@oracle.com> wrote: > > > >>> > > > >>>> > > > >>>> On Dec 6, 2016, at 9:19 AM, Jesus Luzon <jlu...@riotgames.com> wrote: > > > >>>> > > > >>>> Hey Jim, > > > >>>> > > > >>>> I looked at it and I will look into loadWithNewGlobal to see what > > > >>>> exactly it does since it could be relevant. As for the rest, for my > > > >>>> use > > > >>>> case having threads in the JS would not help. We're using Nashorn to > > > >>>> build > > > >>>> JSON filters in a Dynamic Proxy Service and need any of the threads > > > >>>> processing a request to be able to execute the script to filter. > > > >>>> > > > >>>> > > > >>>> The cost of creating a new engine is significant. So share an engine > > > >>>> across threads but use *eval > > > >>>> <https://docs.oracle.com/javase/7/docs/api/javax/script/ScriptEngine.html#eval(java.lang.String,%20javax.script.ScriptContext)>* > > > >>>> (String > > > >>>> <https://docs.oracle.com/javase/7/docs/api/java/lang/String.html> > > > >>>> script, ScriptContext > > > >>>> <https://docs.oracle.com/javase/7/docs/api/javax/script/ScriptContext.html> > > > >>>> context) instead, separate context per execution. If your JavaScript > > > >>>> code does not modify globals you can get away with using the same > > > >>>> engine, > > > >>>> same compiled script on each thread. > > > >>>> > > > >>>> > > > >>>> Also, when you say a new engine per threads is the worst case what > > > >>>> exactly do you mean? I would expect an initial cost of compiling the > > > >>>> script > > > >>>> on each thread and then each engine should be able to do its own > > > >>>> thing, but > > > >>>> what I'm seeing is that when running with more than 10 threads all my > > > >>>> engines get slow at executing code, even though they are all > > > >>>> completely > > > >>>> separate from each other. > > > >>>> > > > >>>> > > > >>>> Of course there are many factors involved n performance. How many > > > >>>> cores > > > >>>> do you have on the test machine? How much memory in the process? > > > >>>> What > > > >>>> transport are you using between threads? That sort of thing. Other > > > >>>> than > > > >>>> constructing then engine and context Nashorn performance should > > > >>>> scale. > > > >>>> > > > >>>> > > > >>>> On Tue, Dec 6, 2016 at 5:07 AM, Jim Laskey (Oracle) < > > > >>>> james.las...@oracle.com> wrote: > > > >>>> > > > >>>>> Jesus, > > > >>>>> > > > >>>>> Probably the most informative information is in this blog. > > > >>>>> > > > >>>>> https://blogs.oracle.com/nashorn/entry/nashorn_multi_threading_and_mt > > > >>>>> > > > >>>>> This example uses Executors but threads would work as well. > > > >>>>> > > > >>>>> I did a talk that looked at different methods to max out > > > >>>>> multithreading > > > >>>>> performance. A new engine per thread is the worst case. A new > > > >>>>> context per > > > >>>>> thread does much better. A new global per thread is the best while > > > >>>>> remaining thread safe. > > > >>>>> > > > >>>>> Cheers, > > > >>>>> > > > >>>>> — Jim > > > >>>>> > > > >>>>> > > > >>>>> > > > >>>>> > > > >>>>> > > > >>>>> On Dec 6, 2016, at 8:45 AM, Jesus Luzon <jlu...@riotgames.com> > > > >>>>> wrote: > > > >>>>> > > > >>>>> Hey folks, > > > >>>>> > > > >>>>> I've tried many different ways of using Nashorn multithreaded based > > > >>>>> on > > > >>>>> what > > > >>>>> I've found on the internet and I still can't get a single one to > > > >>>>> scale. > > > >>>>> Even the most naive method of making many script engines with my > > > >>>>> script > > > >>>>> tends to bottleneck itself when I have more than 10 threads invoking > > > >>>>> functions. > > > >>>>> > > > >>>>> I'm using the following code to compile my script and > > > >>>>> invocable.invokeFunction("transform", input) to execute: > > > >>>>> > > > >>>>> static Invocable generateInvocable(String script) throws > > > >>>>> ScriptException { > > > >>>>> ScriptEngineManager manager = new ScriptEngineManager(); > > > >>>>> ScriptEngine engine = > > > >>>>> manager.getEngineByName(JAVASCRIPT_ENGINE_NAME); > > > >>>>> Compilable compilable = (Compilable) engine; > > > >>>>> final CompiledScript compiled = compilable.compile(script); > > > >>>>> compiled.eval(); > > > >>>>> return (Invocable) engine; > > > >>>>> } > > > >>>>> > > > >>>>> > > > >>>>> > > > >>>>> The script I'm compiling is: > > > >>>>> > > > >>>>> String script = "function transform(input) {" + > > > >>>>> "var result = JSON.parse(input);" + > > > >>>>> "response = {};\n" + > > > >>>>> "for (var i = 0; i < result.length; i++) {\n" + > > > >>>>> " var summoner = {};\n" + > > > >>>>> " summoner.id = result[i].id;\n" + > > > >>>>> " summoner.name = result[i].name;\n" + > > > >>>>> " summoner.profileIconId = > > > >>>>> result[i].profileIconId;\n" + > > > >>>>> " summoner.revisionDate = > > > >>>>> result[i].revisionDate;\n" + > > > >>>>> " summoner.summonerLevel = result[i].level;\n" + > > > >>>>> " response[summoner.id] = summoner;\n" + > > > >>>>> "}\n" + > > > >>>>> "result = response;" + > > > >>>>> "return JSON.stringify(result);" + > > > >>>>> "};"; > > > >>>>> > > > >>>>> > > > >>>>> > > > >>>>> I've also tried other more scaleable ways to work with scripts > > > >>>>> concurrently, but given that this is the most naive method where > > > >>>>> everything > > > >>>>> is brand new and I still get slowness calling them concurrently I > > > >>>>> fear > > > >>>>> that > > > >>>>> maybe I'm overlooking something extremely basic on my code. > > > >>>>> > > > >>>>> Thanks. > > > >>>>> -Jesus Luzon > > > >>>>> > > > >>>>> > > > >>>> > > > >>> > > > >>> > > > >> > > > >> > > > > > > > > > > > > > > > > > >