From kevinz5000 at gmail.com Sun Mar 1 13:01:41 2020 From: kevinz5000 at gmail.com (Kevin Zheng) Date: Sun, 1 Mar 2020 11:01:41 -0800 Subject: [crossfire] Proposal to move server/lib/ files to arch/ Message-ID: <27d61ed7-c89b-14df-dd38-feca36d55572@gmail.com> Hi there, I'm proposing to move these non-generated files in server/lib to arch: artifacts attackmess formulae image_info materials messages races Logically, the information here belongs with archs, since if the archs change these should change too. Moving them to arch, where they belong, should also discourage server tree divergence with those who are running custom maps/archs, so that it is easier to run with the same server. These will still only be installed along with the server build, but the server build already requires a symlink to the arch directory. Regards, Kevin -- Kevin Zheng kevinz5000 at gmail.com | kevinz at berkeley.edu XMPP: kevinz at eecs.berkeley.edu From nkipps at gmail.com Sun Mar 1 14:30:56 2020 From: nkipps at gmail.com (Nathaniel Kipps) Date: Sun, 1 Mar 2020 15:30:56 -0500 Subject: [crossfire] Proposal to move server/lib/ files to arch/ In-Reply-To: <27d61ed7-c89b-14df-dd38-feca36d55572@gmail.com> References: <27d61ed7-c89b-14df-dd38-feca36d55572@gmail.com> Message-ID: I agree with the theory, it makes sense to me. --DraugTheWhopper On Sun, Mar 1, 2020 at 2:07 PM Kevin Zheng wrote: > > Hi there, > > I'm proposing to move these non-generated files in server/lib to arch: > > artifacts > attackmess > formulae > image_info > materials > messages > races From mwedel at sonic.net Sun Mar 1 23:26:51 2020 From: mwedel at sonic.net (Mark Wedel) Date: Sun, 1 Mar 2020 21:26:51 -0800 Subject: [crossfire] Proposal to move server/lib/ files to arch/ In-Reply-To: <27d61ed7-c89b-14df-dd38-feca36d55572@gmail.com> References: <27d61ed7-c89b-14df-dd38-feca36d55572@gmail.com> Message-ID: <2c34f7ad-523e-1601-6cc7-135e2fb0e1d9@sonic.net> On 3/1/20 11:01 AM, Kevin Zheng wrote: > Hi there, > > I'm proposing to move these non-generated files in server/lib to arch: > > artifacts > attackmess > formulae > image_info > materials > messages > races > > Logically, the information here belongs with archs, since if the archs > change these should change too. Moving them to arch, where they belong, > should also discourage server tree divergence with those who are running > custom maps/archs, so that it is easier to run with the same server. > > These will still only be installed along with the server build, but the > server build already requires a symlink to the arch directory. It makes sense. In an ideal world, some of those files would get broken apart and be located with the relevant archetype (artifacts, formulae come to mind), like the treasures entry was, and then collected. The races was always a bit of a hack - it was put in as an easy way to set a group of races (eg, all undead) without going through and updating all the .arc files - in theory, that file should be redundant if all the race entries for the .arc files are set right, but I suspect there is more to it than just that. From nicolas.weeger at laposte.net Mon Mar 2 12:07:54 2020 From: nicolas.weeger at laposte.net (Nicolas Weeger) Date: Mon, 02 Mar 2020 19:07:54 +0100 Subject: [crossfire] Proposal to move server/lib/ files to arch/ In-Reply-To: <27d61ed7-c89b-14df-dd38-feca36d55572@gmail.com> References: <27d61ed7-c89b-14df-dd38-feca36d55572@gmail.com> Message-ID: <1822849.hdANEeVLPe@gros> Hello. Fine by me too, and I agree with Mark on the idea of splitting those files too :) Best regards Nicolas Le dimanche 1 mars 2020, 11:01:41 CET Kevin Zheng a écrit : > Hi there, > > I'm proposing to move these non-generated files in server/lib to arch: > > artifacts > attackmess > formulae > image_info > materials > messages > races > > Logically, the information here belongs with archs, since if the archs > change these should change too. Moving them to arch, where they belong, > should also discourage server tree divergence with those who are running > custom maps/archs, so that it is easier to run with the same server. > > These will still only be installed along with the server build, but the > server build already requires a symlink to the arch directory. > > Regards, > Kevin -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 195 bytes Desc: This is a digitally signed message part. URL: From kevinz5000 at gmail.com Mon Mar 2 21:56:54 2020 From: kevinz5000 at gmail.com (Kevin Zheng) Date: Mon, 2 Mar 2020 19:56:54 -0800 Subject: [crossfire] Proposal to move server/lib/ files to arch/ In-Reply-To: <1822849.hdANEeVLPe@gros> References: <27d61ed7-c89b-14df-dd38-feca36d55572@gmail.com> <1822849.hdANEeVLPe@gros> Message-ID: <5bb546c2-f434-67f5-a68c-9bae8048fb6a@gmail.com> Thanks to those who chimed in with feedback. Committed in r21127 and r21128. This changes how release tarballs need to be generated. Specifically, when creating the source release tarball, there needs to be a server/lib/arch directory containing those moved files. I realize that `make dist` has been broken for some time. Once I manage to fix `make dist` this manual step should not be needed. Regards, Kevin -- Kevin Zheng kevinz5000 at gmail.com | kevinz at berkeley.edu XMPP: kevinz at eecs.berkeley.edu From davidnicholashurst at gmail.com Wed Mar 4 06:22:49 2020 From: davidnicholashurst at gmail.com (David Hurst) Date: Wed, 4 Mar 2020 23:22:49 +1100 Subject: [crossfire] Proposal to move server/lib/ files to arch/ In-Reply-To: <5bb546c2-f434-67f5-a68c-9bae8048fb6a@gmail.com> References: <27d61ed7-c89b-14df-dd38-feca36d55572@gmail.com> <1822849.hdANEeVLPe@gros> <5bb546c2-f434-67f5-a68c-9bae8048fb6a@gmail.com> Message-ID: Brilliant fix, the old location of these was very counter intuitive. Saru On Tue, 3 Mar 2020 at 15:02, Kevin Zheng wrote: > Thanks to those who chimed in with feedback. > > Committed in r21127 and r21128. > > This changes how release tarballs need to be generated. Specifically, > when creating the source release tarball, there needs to be a > server/lib/arch directory containing those moved files. > > I realize that `make dist` has been broken for some time. Once I manage > to fix `make dist` this manual step should not be needed. > > Regards, > Kevin > > -- > Kevin Zheng > kevinz5000 at gmail.com | kevinz at berkeley.edu > XMPP: kevinz at eecs.berkeley.edu > _______________________________________________ > crossfire mailing list > crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ephraim.baker at yahoo.com Wed Mar 4 15:15:41 2020 From: ephraim.baker at yahoo.com (bill billy) Date: Wed, 4 Mar 2020 21:15:41 +0000 (UTC) Subject: [crossfire] Devourers dungeon development, collaborations welcome! References: <659005391.4495949.1583356541468.ref@mail.yahoo.com> Message-ID: <659005391.4495949.1583356541468@mail.yahoo.com> As the title suggests, I'm putting together a new dungeon for the Devourer cult, I'd love to hear ideas, suggestions or even get some direct collaboration!  Here's what I've got so far: Devourers exist in a collection of 'void space' maps which represent a dark place between worlds, accessible by moving in an 'impossible angle'. The 'impossible angles' are secret corners throughout the world which appear normal but when stepped into will behave as an exit. The Void is a non-euclidean space occupied by nightmares, mist, the back sides of the various exits throughout the over-world and a hidden path which leads to the nest of the Devourers. An experienced player would be able to possibly learn how to use the void to fast travel from place to place; hopefully soft balanced through non-euclidean geometry. The path to the Devourers nest requires a player to find a way to map this space in order to eventually find a branch which leads off from the central mass of basic void maps. Currently using Skree's as placeholders for the Devourers but I'm not overly married too much to this original idea. I like the idea of a parallel dimension instead of a traditional dungeon and also having this other use (fast travel). Additional notes: On Heroworld I've hidden a few secrets in the Void such as a version of the original Scorn. --- HW also has a /death map players go to when they die where they have an option of avoiding the penalty of death. I've placed a door in /death which, when unlocked, will let a player avoid the resurrection process all together by escaping into the void. --- Petrification arrows exist on HW. When a player is petrified he will them be teleported to an island in the void and replaced by a race-specific statue showing name and level. -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevinz5000 at gmail.com Tue Mar 10 01:24:29 2020 From: kevinz5000 at gmail.com (Kevin Zheng) Date: Mon, 9 Mar 2020 23:24:29 -0700 Subject: [crossfire] Proposal: retire MAX_OBJECTS and object allocator Message-ID: <0465c02b-10ec-22b1-cd6c-829e86c0c2f7@gmail.com> Hi there, After experiencing MAX_OBJECTS-related excessive swapping on Invidious that allowed Saromok's souped-up goblins to poison and kill my character, I've decided to take another look at memory management. I may be missing some historical context for why things are the way they currently are in Crossfire, so I welcome feedback on what these proposed changes might do or not do. The rationale for each change is included in each patch, but reproduced here for convenience: Subject: [PATCH 1/2] Retire MAX_OBJECTS MAX_OBJECTS has probably outlived its usefulness. It was previously "no hard limit," only serving to trigger map swapping immediately after loading a map, if the number of used objects exceeded MAX_OBJECTS. At worse case, MAX_OBJECTS causes an O(n^2) search and O(n) swaps, where n is the number of maps in memory. This happens immediately after loading a very large map. The server takes O(n) to search for the map with the smallest remaining timeout and swaps it, and does this n times or until enough memory is freed. If the other maps are small, this does not free much memory and causes the "performance hit" mentioned in the comments. This was observed on Invidious, where the server experienced delays of up to 700 ms immediately after loading a large map due to excessive swapping. Removing MAX_OBJECTS does not significantly change the server's allocation pattern because the server never frees memory (it maintains an internal free list) and because maps are swapped out based on timeout at the end of each tick anyway. Subject: [PATCH 2/2] Retire object allocator The object allocator allocates OBJ_EXPAND objects at a time and manages its own free list. It is faster at allocating many objects at once, but defeats memory debuggers and mitigation techniques. It also does not return unused memory to the operating system. Rewrite object_new() to always allocate memory using calloc(). This will incur some memory overhead since an object struct does not fit perfectly into a nice allocator slab size. object_free2() adds freed objects to a free list that is reclaimed at the end of each server tick. It cannot immediately free object memory, because some callers expect to be able to query it for FLAG_FREED to detect object removal. These changes were tested locally (mostly by running a character around) with 1) clang -fsanitize=address, which did not report any errors, and 2) with Jemalloc statistics enabled (see attached, jemalloc.out). As expected, after the change, the allocator bin seeing the most activity was 768 bytes (struct object is 656 bytes on x86-64). -- Kevin Zheng kevinz5000 at gmail.com | kevinz at berkeley.edu XMPP: kevinz at eecs.berkeley.edu -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-Retire-MAX_OBJECTS.patch Type: text/x-patch Size: 8575 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 0002-Retire-object-allocator.patch Type: text/x-patch Size: 11623 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: jemalloc.out Type: text/x-maxima-out Size: 16044 bytes Desc: not available URL: From mwedel at sonic.net Tue Mar 10 23:56:57 2020 From: mwedel at sonic.net (Mark Wedel) Date: Tue, 10 Mar 2020 21:56:57 -0700 Subject: [crossfire] Proposal: retire MAX_OBJECTS and object allocator In-Reply-To: <0465c02b-10ec-22b1-cd6c-829e86c0c2f7@gmail.com> References: <0465c02b-10ec-22b1-cd6c-829e86c0c2f7@gmail.com> Message-ID: On 3/9/20 11:24 PM, Kevin Zheng wrote: > Hi there, > > After experiencing MAX_OBJECTS-related excessive swapping on Invidious > that allowed Saromok's souped-up goblins to poison and kill my > character, I've decided to take another look at memory management. > > I may be missing some historical context for why things are the way they > currently are in Crossfire, so I welcome feedback on what these proposed > changes might do or not do. Crossfire goes way back (30+ years at this point), and the power/abilities of those machines back then were much more limited. I think back then, the computer I was using had 16 megs of memory. As such, things like memory consumption was much more a concern, and while memory usage has gone up (more stuff stored in the object, larger maps, etc), it has not gone up at the same pace as computer power has gone up. So a lot of those old assumptions are no longer true. > > The rationale for each change is included in each patch, but reproduced > here for convenience: > > > Subject: [PATCH 1/2] Retire MAX_OBJECTS > > MAX_OBJECTS has probably outlived its usefulness. It was previously "no > hard limit," only serving to trigger map swapping immediately after > loading a map, if the number of used objects exceeded MAX_OBJECTS. > > At worse case, MAX_OBJECTS causes an O(n^2) search and O(n) swaps, where > n is the number of maps in memory. This happens immediately after > loading a very large map. The server takes O(n) to search for the map > with the smallest remaining timeout and swaps it, and does this n times > or until enough memory is freed. If the other maps are small, this does > not free much memory and causes the "performance hit" mentioned in the > comments. This was observed on Invidious, where the server experienced > delays of up to 700 ms immediately after loading a large map due to > excessive swapping. > > Removing MAX_OBJECTS does not significantly change the server's > allocation pattern because the server never frees memory (it maintains > an internal free list) and because maps are swapped out based on timeout > at the end of each tick anyway. This totally makes sense - as alluded to above, at one time, memory was constrained and one wanted to make sure crossfire did not use so much memory as to cause paging on the system it was running on. In theory, MAX_OBJECTS would get tuned by each administrator, based on how much memory their server had, but I think that rarely happened. > > > Subject: [PATCH 2/2] Retire object allocator > > The object allocator allocates OBJ_EXPAND objects at a time and manages > its own free list. It is faster at allocating many objects at once, but > defeats memory debuggers and mitigation techniques. It also does not > return unused memory to the operating system. Not sure if still the case, but at one time, performance of allocating thousands of new objects individually increased lag (when loading new maps). So doing it in blocks of 500 or whatever was faster. At one point I had put in option to do individually allocation, simply for the reason above - if using a memory debugger, that block of objects failed to work. Minor nit - even free() on a memory object does not return it to the OS - it tells malloc that block of memory is available again, and on a future call, malloc will re-use it, though you can get fragmentation (malloc may decide to use that memory for something smaller than an object). > > Rewrite object_new() to always allocate memory using calloc(). This will > incur some memory overhead since an object struct does not fit perfectly > into a nice allocator slab size. I suspect additional overhead should be pretty trivial, assuming the allocator is decent (and realistically, not much an issue anyways) > > object_free2() adds freed objects to a free list that is reclaimed at > the end of each server tick. It cannot immediately free object memory, > because some callers expect to be able to query it for FLAG_FREED to > detect object removal. querying for flag freed was always a bit buggy (it sort of relies that the given object won't get re-used, which works because the program is singled threaded and these freed objects will be last to be allocated when new objects are needed again). Also, as noted above, since memory is not returned to the OS, only the allocator, having crossfire itself keep a freelist makes perfect sense - it is going to need those objects again at some point, and objects are the main use of dynamic memory. If the program did something like was in one state where it needed a bunch of malloc'd items, and did something with them, no longer needed them, but then needed a large amount of memory for a different object type, freeing them would make sense, because in that second allocation, it could re-use that freed up space. From kevinz5000 at gmail.com Wed Mar 11 00:30:48 2020 From: kevinz5000 at gmail.com (Kevin Zheng) Date: Tue, 10 Mar 2020 22:30:48 -0700 Subject: [crossfire] Proposal: retire MAX_OBJECTS and object allocator In-Reply-To: References: <0465c02b-10ec-22b1-cd6c-829e86c0c2f7@gmail.com> Message-ID: <2075ad55-a51f-e2bb-a24c-c897a43b1356@gmail.com> Thanks, Mark, for the review. On 3/10/20 9:56 PM, Mark Wedel wrote: >> The object allocator allocates OBJ_EXPAND objects at a time and manages >> its own free list. It is faster at allocating many objects at once, but >> defeats memory debuggers and mitigation techniques. It also does not >> return unused memory to the operating system. > >  Not sure if still the case, but at one time, performance of allocating > thousands of new objects individually increased lag (when loading new > maps).  So doing it in blocks of 500 or whatever was faster.  At one > point I had put in option to do individually allocation, simply for the > reason above - if using a memory debugger, that block of objects failed > to work. I have not measured the latency loading maps. I'll measure this and hopefully get back with some results. >  Minor nit - even free() on a memory object does not return it to the OS > - it tells malloc that block of memory is available again, and on a > future call, malloc will re-use it, though you can get fragmentation > (malloc may decide to use that memory for something smaller than an > object). This may be true for some allocators, but not jemalloc. Now, not all allocators are jemalloc and that might be important to consider. In jemalloc, unused dirty pages are kept around for re-allocation but eventually "returned" to the operating system via madvise(...MADV_FREE). top confirms that the server's resident memory can drop below its peak resident memory when no swapping takes place. The jemalloc statistics show the number of madvise() calls. Linux appears to have gained MADV_FREE since 4.5, but I'm not sure if the standard library allocator uses it. >> object_free2() adds freed objects to a free list that is reclaimed at >> the end of each server tick. It cannot immediately free object memory, >> because some callers expect to be able to query it for FLAG_FREED to >> detect object removal. > >  querying for flag freed was always a bit buggy (it sort of relies that > the given object won't get re-used, which works because the program is > singled threaded and these freed objects will be last to be allocated > when new objects are needed again). > >  Also, as noted above, since memory is not returned to the OS, only the > allocator, having crossfire itself keep a freelist makes perfect sense - > it is going to need those objects again at some point, and objects are > the main use of dynamic memory.   If the program did something like was > in one state where it needed a bunch of malloc'd items, and did > something with them, no longer needed them, but then needed a large > amount of memory for a different object type, freeing them would make > sense, because in that second allocation, it could re-use that freed up > space. I suppose this boils down to how much slower calloc() is compared to grabbing from the internal freelist, and whether free() returns memory on enough supported operating systems or not. -- Kevin Zheng kevinz5000 at gmail.com | kevinz at berkeley.edu XMPP: kevinz at eecs.berkeley.edu From kevinz5000 at gmail.com Wed Mar 11 13:08:45 2020 From: kevinz5000 at gmail.com (Kevin Zheng) Date: Wed, 11 Mar 2020 11:08:45 -0700 Subject: [crossfire] Proposal: retire MAX_OBJECTS and object allocator In-Reply-To: References: <0465c02b-10ec-22b1-cd6c-829e86c0c2f7@gmail.com> Message-ID: <87d181ec-ed7a-759e-be20-546f38cf05c7@gmail.com> On 3/10/20 9:56 PM, Mark Wedel wrote: >  Not sure if still the case, but at one time, performance of allocating > thousands of new objects individually increased lag (when loading new > maps).  So doing it in blocks of 500 or whatever was faster.  At one > point I had put in option to do individually allocation, simply for the > reason above - if using a memory debugger, that block of objects failed > to work. Allocating one object at a time does make mapfile_load() slower (all numbers in us): x CF Object Allocator + 1 object per calloc() +----------------------------------------------------------------------+ | x + | |x x x x x*x x+ + + + + + + +| | |_________A_M______| |_______________A_M_____________| | +----------------------------------------------------------------------+ N Min Max Median Avg Stddev x 10 16154 17814 17309.5 17148.7 579.95633 + 10 17560 20576 19169 19021.9 1033.7963 Difference at 95.0% confidence 1873.2 +/- 787.548 10.9233% +/- 4.71741% (Student's t, pooled s = 838.178) This measurement was made with n=10 loading /world/world_105_115 with a warm disk cache, with a newly started server each time so that memory fragmentation hasn't occurred. Time elapsed was measured with a monotonic clock. It looks like 1-object-per-alloc increases the median by 2 ms. For tiled world maps, at worse case 5 maps are loaded at a time, for a total additional latency of 10 ms, or about a 11% increase. -- Kevin Zheng kevinz5000 at gmail.com | kevinz at berkeley.edu XMPP: kevinz at eecs.berkeley.edu From mwedel at sonic.net Thu Mar 12 00:18:20 2020 From: mwedel at sonic.net (Mark Wedel) Date: Wed, 11 Mar 2020 22:18:20 -0700 Subject: [crossfire] Proposal: retire MAX_OBJECTS and object allocator In-Reply-To: <87d181ec-ed7a-759e-be20-546f38cf05c7@gmail.com> References: <0465c02b-10ec-22b1-cd6c-829e86c0c2f7@gmail.com> <87d181ec-ed7a-759e-be20-546f38cf05c7@gmail.com> Message-ID: <2d50087c-8f7d-d09d-d04a-24458ef1b154@sonic.net> On 3/11/20 11:08 AM, Kevin Zheng wrote: > On 3/10/20 9:56 PM, Mark Wedel wrote: >>  Not sure if still the case, but at one time, performance of allocating >> thousands of new objects individually increased lag (when loading new >> maps).  So doing it in blocks of 500 or whatever was faster.  At one >> point I had put in option to do individually allocation, simply for the >> reason above - if using a memory debugger, that block of objects failed >> to work. > > Allocating one object at a time does make mapfile_load() slower (all > numbers in us): > > x CF Object Allocator > + 1 object per calloc() > +----------------------------------------------------------------------+ > | x + | > |x x x x x*x x+ + + + + + + +| > | |_________A_M______| |_______________A_M_____________| | > +----------------------------------------------------------------------+ > N Min Max Median Avg Stddev > x 10 16154 17814 17309.5 17148.7 579.95633 > + 10 17560 20576 19169 19021.9 1033.7963 > Difference at 95.0% confidence > 1873.2 +/- 787.548 > 10.9233% +/- 4.71741% > (Student's t, pooled s = 838.178) > > This measurement was made with n=10 loading /world/world_105_115 with a > warm disk cache, with a newly started server each time so that memory > fragmentation hasn't occurred. Time elapsed was measured with a > monotonic clock. > > It looks like 1-object-per-alloc increases the median by 2 ms. For tiled > world maps, at worse case 5 maps are loaded at a time, for a total > additional latency of 10 ms, or about a 11% increase. I thought it was be slower, but for modern hardware, that is not very much (going back to the system that had 16 megs of memory, its CPU also run at 25 mhz I think, so ignoring architectural differences, still clearly a lot faster). Given those old system were maybe 100 times slower, that mean loading the map would take 200 ms, and given tick time hasn't really changed, that means lag. However, even in current architecture, this really isn't a problem - since objects are never freed, eventually the game gets to a point where it should enough have objects on the free list that it doesn't need to allocate objects very often. So after the server first starts up, things may be sort of slow until it sort of reaches that point.