View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0000873 | LDMud | Other | public | 2020-01-10 18:41 | 2020-04-28 22:26 |
Reporter | realms-mud | Assigned To | Gnomi | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Summary | 0000873: LDMud 3.6.* performance significantly worse than 3.5.0 | ||||
Description | I noticed that the changes from 3.5.0 to 3.6.0 (and 3.6.1) come with a pretty significant performance hit. Here's some output from one of my more CPU-intensive tests first running with the 3.5.0 driver and then with the 3.6.0 driver. I did test with 3.6.1, but since the speed was roughly the same as 3.6.0, I did not bother throwing that data on here as well: First, 3.5.0: 2020.01.10 12:55:28 LDMud 3.5.0 (3.5.0) (release) Compiling file: /lib/tests/modules/crafting/craftWeaponTest.c Testing lib/tests/modules/crafting/craftWeaponTest [ PASSED ] CraftSelectedOptionBecomesEnabledWhenAllCriteriaMet (5181ms) [ PASSED ] ChoosingCraftSelectedFailsWhenDisabled (135ms) [ PASSED ] CraftingASwordGeneratesTheCorrectItemAndReducesMaterials (197ms) [ PASSED ] CraftingIsNotAffectedByNotApplicableLimitedByCraftingTypeResearch (186ms) [ PASSED ] CraftingItemIsNotAffectedByCraftingBonusesWhenOfDifferentType (190ms) [ PASSED ] CraftingItemIsAffectedByCraftingBonusesWhenOfType (188ms) [ PASSED ] CraftingSetsEnchantments (369ms) Test executed: lib/tests/modules/crafting/craftWeaponTest -> [ PASSED ] -> built in 6484 ms. Next, 3.6.0 - 2020.01.10 12:55:48 LDMud 3.6.0 (3.6.0) (release) Compiling file: /lib/tests/modules/crafting/craftWeaponTest.c Testing lib/tests/modules/crafting/craftWeaponTest [ PASSED ] CraftSelectedOptionBecomesEnabledWhenAllCriteriaMet (11437ms) [ PASSED ] ChoosingCraftSelectedFailsWhenDisabled (370ms) [ PASSED ] CraftingASwordGeneratesTheCorrectItemAndReducesMaterials (458ms) [ PASSED ] CraftingIsNotAffectedByNotApplicableLimitedByCraftingTypeResearch (469ms) [ PASSED ] CraftingItemIsNotAffectedByCraftingBonusesWhenOfDifferentType (489ms) [ PASSED ] CraftingItemIsAffectedByCraftingBonusesWhenOfType (481ms) [ PASSED ] CraftingSetsEnchantments (783ms) Test executed: lib/tests/modules/crafting/craftWeaponTest -> [ PASSED ] -> built in 14553 ms. For my entire test suite, the overall execution time went from roughly 6:45 minutes to around 11:00 minutes over a half dozen runs and every test in my test suite is 30% to 100+% slower. I am also able to see this performance issue in-game, but it's much harder to accurately measure. Anecdotally, I can definitely see things that take a hundred ms in 3.5 take "a lot longer" in 3.6, but my test framework is a much more reliable measure. | ||||
Steps To Reproduce | Find any object of observable complexity with which you can evaluate a method and execute it in both 3.5 and 3.6. | ||||
Tags | No tags attached. | ||||
Attached Files | |||||
External Data (URL) | |||||
|
You need to give us some more code to test it on. I checked some of our tests in the test suite and they ran in the same time in both versions. And in our production MUD we don't have any that long running code. |
|
I'm trying to find something that doesn't cascade into a really painful example but I'm not having too much luck. That said, it looks like a decent test would be to grab the following files from my repo: The test is: https://github.com/realms-mud/core-lib/blob/master/lib/tests/items/itemTest.c For this, you can comment out every method after CanSetBonusesOnItems() as this test takes on average 220ms on 3.5 and 470ms on 3.6 - most appears to be time spent in load_object on all of the dependencies, for what that's worth. This has quite a few dependencies, but it should work if you just copy over the /lib directory and all of its contents to <root>/lib on your instance (ie: you will need your own master, simul_efun, etc), but any should be fine: https://github.com/realms-mud/core-lib/tree/master/lib Do not try to copy the rest of the mudlib over because that would bring some database dependencies (and needed DB structure) over and I don't think we want to go there. To execute the test, you should be able to just do: load_object("/lib/tests/items/itemTest.c")->executeTests(); If this becomes painful for you, I can get you a running environment to work with. |
|
I added a simul-efun for format() and regreplace(), but now I get a runtime error: 2020.01.11 11:50:59 Item: The 'bonus <thing>' element must be a string as defined in the keys of the bonusList mapping in /lib/dictionaries/bonusesDictionary.c and it must be set to an appropriate value. 2020.01.11 11:50:59 program: lib/items/item.c, object: lib/items/item#0 line 93 38 ' epilog' in ' master.c' (' master') line 27 137 ' run_test' in ' master.c' (' master') line 15 36498 ' executeTests' in 'lib/tests/framework/testFixture.c' ('lib/tests/items/itemTest') line 47 74158 'CanSetBonusesOnItems' in 'lib/tests/items/itemTest.c' ('lib/tests/items/itemTest') line 27 74194 ' set' in ' lib/items/item.c' (' lib/items/item#0') line 514 74285 ' isValidBonus' in ' lib/items/item.c' (' lib/items/item#0') line 93 2020.01.11 11:50:59 Error in master_ob->epilog() |
|
Sorry about that. I'd forgotten about my format efun, but regreplace should just be the standard efun. For format(string, int), it just deals with line-wrap, so returning the passed-in string would be fine. If I had to guess (which, admittedly, this would be a blind guess), the file_size(...) check on line 65 of lib/items/item.c would almost certainly be the culprit since that is typically a privileged check in valid_read. I know I do have some file_size(...) checks in a few other places throughout the codebase. Are you using a master/simul_efun that I have access to? If so, I can get this running locally and given you something that'll work "out of the box" rather than playing tag on this. |
|
This is my master (the inc and sys directory are from ldmud's test directory):#include "/inc/base.inc" #include "/inc/sefun.inc" void run_test() { object ob; int *start, *end; msg("\nRealms-MUD test\n" "---------------\n"); ob = load_object("lib/tests/items/itemTest"); start = utime(); ob->executeTests(); end = utime(); msg("Duration: %d\n", (end[0] - start[0]) * 1000000 + end[1] - start[1]); shutdown(0); return 0; } string *epilog(int eflag) { set_driver_hook(H_INCLUDE_DIRS, ({ "/sys/"})); run_test(); return 0; } And this the simul-efun: string format(string str, int width) { return str; } varargs string regreplace(string txt, string pattern, string|closure replacepattern, int flags) { return efun::regreplace(txt, pattern, replacepattern, flags); } |
|
Since I wasn't able to use your master.c (has a couple include files I don't have), I grabbed (a really awful) one that works. You should be able to just untar this tarball somewhere as a root mudlib directory and point the driver at it. Thanks for your efforts! |
|
As I wrote the inc and sys directories are in the directory /test in the LDMud sources. |
|
I guess reading is hard for me. ;) |
|
It looks like all you need to do to "fix" the issue you're seeing is to change the CanSetBonusesOnItems test to remove the setup/check for "bonus fire attack". Reset isn't getting called on the objects loaded for that.... keeping that in the test is not really important in this context and only changes the execution time by about 5ms on average. IE: Change lib/tests/items/itemTest.c to just be: <code> inherit "/lib/tests/framework/testFixture.c"; object Item; void Setup() { Item = clone_object("/lib/items/item"); } void CleanUp() { destruct(Item); } void CanSetBonusesOnItems() { // Only test a few of these - the full set is tested in dictionaries/bonusesDictionaryTest ExpectFalse(Item->query("enchanted"), "item is enchanted"); ExpectTrue(Item->set("bonus armor class", 5), "bonus armor class can be set"); ExpectTrue(Item->set("bonus gem crafting", 7), "bonus armor class can be set"); ExpectEq(5, Item->query("bonus armor class"), "bonus armor class query returns correctly"); ExpectEq(7, Item->query("bonus gem crafting"), "bonus gem crafting query returns correctly"); ExpectTrue(Item->query("enchanted"), "item is enchanted"); } </code> |
|
... and the Mantis Wiki let me down... apologies for the fubar formatting. |
|
I can reproduce it and will look into it. |
|
Could you try the optimization branch in my repository: https://github.com/amotzkau/ldmud/tree/optimization I found that the most of the extra time was spent on passing the source files through iconv(). As ASCII or UTF-8 files will be the most common case I implemented a shortcut for that, that just checks the input. These checks also have extra costs in comparison to 3.5.2, but they are necessary. I would be interested how this optimization does with your test suite. The test case I have runs between 31 and 35ms, so the difference to 3.5.2 is within the margin of error... |
|
I did a few test runs and the results look really good: 3.5: Test executed: lib/tests/modules/crafting/craftWeaponTest -> [ PASSED ] -> built in 6387 ms. 3.6: Test executed: lib/tests/modules/crafting/craftWeaponTest -> [ PASSED ] -> built in 14722 ms. Your optimization: Test executed: lib/tests/modules/crafting/craftWeaponTest -> [ PASSED ] -> built in 6892 ms A much faster test (the full itemTest.c I pointed you to earlier): 3.5: 149ms 3.6: 241ms Your optimizations: 168ms There's definitely a little overhead, but it's not linear like it was and overall I'd say it's pretty negligible. |
|
I think, it is also worth pointing out that your test suite is performing that bad on 3.6.x concerning the performance because it is so heavily compiling lots of programs. Once an object is loaded, there should be not much slowdown. |
|
Optimization was released in LDMud 3.6.2 |
Date Modified | Username | Field | Change |
---|---|---|---|
2020-01-10 18:41 | realms-mud | New Issue | |
2020-01-10 19:01 | Gnomi | Note Added: 0002498 | |
2020-01-10 19:01 | Gnomi | Assigned To | => Gnomi |
2020-01-10 19:01 | Gnomi | Status | new => feedback |
2020-01-10 21:37 | realms-mud | Note Added: 0002499 | |
2020-01-10 21:37 | realms-mud | Status | feedback => assigned |
2020-01-11 10:53 | Gnomi | Note Added: 0002500 | |
2020-01-13 16:19 | realms-mud | Note Added: 0002507 | |
2020-01-13 16:23 | Gnomi | Note Added: 0002508 | |
2020-01-13 19:06 | realms-mud | File Added: test.tar.gz | |
2020-01-13 19:06 | realms-mud | Note Added: 0002509 | |
2020-01-13 19:25 | Gnomi | Note Added: 0002510 | |
2020-01-13 19:32 | realms-mud | Note Added: 0002511 | |
2020-01-13 20:12 | realms-mud | Note Added: 0002512 | |
2020-01-13 20:13 | realms-mud | Note Added: 0002513 | |
2020-01-14 10:20 | Gnomi | Note Added: 0002518 | |
2020-01-14 20:49 | Gnomi | Note Added: 0002519 | |
2020-01-14 23:43 | realms-mud | Note Added: 0002520 | |
2020-01-18 16:30 | zesstra | Note Added: 0002521 | |
2020-04-28 22:26 | Gnomi | Status | assigned => resolved |
2020-04-28 22:26 | Gnomi | Resolution | open => fixed |
2020-04-28 22:26 | Gnomi | Note Added: 0002530 |