* GC Warning related to large mem block allocation - Help needed @ 2017-12-30 1:48 David Pirotte 2017-12-30 2:35 ` David Pirotte 2017-12-30 4:05 ` David Pirotte 0 siblings, 2 replies; 8+ messages in thread From: David Pirotte @ 2017-12-30 1:48 UTC (permalink / raw) To: guile-devel [-- Attachment #1: Type: text/plain, Size: 3127 bytes --] Hello, Currently, using guile-cv upon large images triggers these warnings, using guile guile 2.2.3: GC Warning: Repeated allocation of very large block (appr. size 775237632): May lead to memory leak and poor performance. ... then 1 '=' above msg per block allocation, tens to hundreds, sometimes even thousands of these, depending on the image processing being done ... These are totally unnecessary (I know I'm allocating these blocks), renders the repl 'output' unreadable/unusable and actually scare users (well, I only have one user for now). So I am trying to understand and solve this problem. Below a (naive) attempt to patch guile so it uses GC_malloc_ignore_off_page for objects > 100Kb, but that did not even work: I guess I do miss most if not all of the puzzle pieces here... While I wrote this tiny patch, 2 quiz also raised in my mind, here there are, together with the naive patch (below): 1- should this function return volatile ? (and how) In bwd-gc README file you can read: https://github.com/ivmai/bdwgc GC_malloc_ignore_off_page(bytes) Identical to GC_malloc, but the client promises to keep a pointer to the somewhere within the first 256 bytes of the object while it is live. (This pointer should normally be declared volatile to prevent interference from compiler optimizations.) This is the recommended way to allocate anything that is likely to be larger than 100 Kbytes or so. (GC_malloc may result in failure to reclaim such objects.) and if yes, how would I achieve this since this function has multiple return calls (with different pointer type) ? 2- I don't understand the last return 'case' ... return scm_inline_gc_alloc (&thread->freelists[idx], idx, SCM_INLINE_GC_KIND_NORMAL); ... How should that be patched so it also use GC_malloc_ignore_off_page(bytes) when bytes > 100Kb? Thanks, David ;;; ;;; Below the patch that does not work :) ;;; From 0ae4f18e478b2e390de72f560ff8428edfeda860 Mon Sep 17 00:00:00 2001 From: David PIROTTE <david@altosw.be> Date: Fri, 29 Dec 2017 22:40:52 -0200 Subject: [PATCH] Use GC_malloc_ignore_off_page for objects > 100Kb * libguile/gc-inline.h (scm_inline_gc_malloc): Use GC_malloc_ignore_off_page for objects > 100Kb. --- libguile/gc-inline.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libguile/gc-inline.h b/libguile/gc-inline.h index fcbe5a54e..7d02e67cc 100644 --- a/libguile/gc-inline.h +++ b/libguile/gc-inline.h @@ -119,8 +119,12 @@ scm_inline_gc_malloc (scm_i_thread *thread, size_t bytes) { size_t idx = scm_inline_gc_bytes_to_freelist_index (bytes); - if (SCM_UNLIKELY (idx >= SCM_INLINE_GC_FREELIST_COUNT)) - return GC_malloc (bytes); + if (SCM_UNLIKELY (idx >= SCM_INLINE_GC_FREELIST_COUNT)) { + if (bytes > 100000) + return GC_malloc_ignore_off_page (bytes); + else + return GC_malloc (bytes); + } return scm_inline_gc_alloc (&thread->freelists[idx], idx, SCM_INLINE_GC_KIND_NORMAL); -- 2.15.0 [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: GC Warning related to large mem block allocation - Help needed 2017-12-30 1:48 GC Warning related to large mem block allocation - Help needed David Pirotte @ 2017-12-30 2:35 ` David Pirotte 2017-12-30 4:05 ` David Pirotte 1 sibling, 0 replies; 8+ messages in thread From: David Pirotte @ 2017-12-30 2:35 UTC (permalink / raw) To: guile-devel [-- Attachment #1: Type: text/plain, Size: 943 bytes --] Hi again, > Currently, using guile-cv upon large images triggers these warnings, > using guile guile 2.2.3: > > GC Warning: Repeated allocation of very large block (appr. size 775237632): > May lead to memory leak and poor performance. Of course you don't need guile-cv to reproduce the problem; if you have enough mem, you can try (or try reducing the mem block, raising the iota arg ...): scheme@(guile-user)> ,use (srfi srfi-4) scheme@(guile-user)> (for-each (lambda (i) (make-f32vector 100000000)) (iota 100)) GC Warning: Repeated allocation of very large block (appr. size 400003072): May lead to memory leak and poor performance. GC Warning: Repeated allocation of very large block (appr. size 400003072): May lead to memory leak and poor performance. GC Warning: Repeated allocation of very large block (appr. size 400003072): May lead to memory leak and poor performance. ... David [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: GC Warning related to large mem block allocation - Help needed 2017-12-30 1:48 GC Warning related to large mem block allocation - Help needed David Pirotte 2017-12-30 2:35 ` David Pirotte @ 2017-12-30 4:05 ` David Pirotte 2017-12-30 5:10 ` Mike Gran 1 sibling, 1 reply; 8+ messages in thread From: David Pirotte @ 2017-12-30 4:05 UTC (permalink / raw) To: guile-devel [-- Attachment #1: Type: text/plain, Size: 1155 bytes --] > So I am trying to understand and solve this problem. Below a (naive) attempt to > patch guile so it uses GC_malloc_ignore_off_page for objects > 100Kb, but that > did not even work: I guess I do miss most if not all of the puzzle pieces here... Obviously (missing all the pieces of the puzzle): I see now that srfi-4 uses srfi-4.c (thanks ijp), which calls scm_i_make_typed_bytevector, defined in bytevectors.c, which calls make_bytevector, which calls scm_gc_malloc_pointerless, which is defined as #define SCM_GC_MALLOC_POINTERLESS(size) GC_MALLOC_ATOMIC (size), which I presume calls BDW-GC GC_malloc_atomic(nbytes) So, (a) the patch below is totally useless for any srfi-4 ops, and (b) it would probably be more interesting to address this GC Warning reports for repeated large block of mem with a 'global' guile approach ... which I unfortunately can't do: I just don't have the knowledge and the experience. I can still try to patch srfi-4.c, for fun and locally, but even that is not easy for me, because I read and write basic C (far from expert level), and I'm quickly lost even just reading libguile code ... David [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: GC Warning related to large mem block allocation - Help needed 2017-12-30 4:05 ` David Pirotte @ 2017-12-30 5:10 ` Mike Gran 2017-12-30 23:38 ` David Pirotte 0 siblings, 1 reply; 8+ messages in thread From: Mike Gran @ 2017-12-30 5:10 UTC (permalink / raw) To: David Pirotte; +Cc: guile-devel On Sat, Dec 30, 2017 at 02:05:21AM -0200, David Pirotte wrote: > > > So I am trying to understand and solve this problem. Below a (naive) attempt to > > patch guile so it uses GC_malloc_ignore_off_page for objects > 100Kb, but that > > did not even work: I guess I do miss most if not all of the puzzle pieces here... If all you are doing is trying to get Guile not to issue warnings about big allocations, I think all you need to do is put -DGC_IGNORE_WARN in the CFLAGS when you build Guile. If you don't or can't rebuild Guile, you might get away with including the following somewhere early in your library. Or it may not work. Dunno. GC_set_warn_proc(GC_ignore_warn_proc); > > Obviously (missing all the pieces of the puzzle): I see now that srfi-4 uses srfi-4.c > (thanks ijp), which calls scm_i_make_typed_bytevector, defined in bytevectors.c, > which calls make_bytevector, which calls scm_gc_malloc_pointerless, which is > defined as #define SCM_GC_MALLOC_POINTERLESS(size) GC_MALLOC_ATOMIC (size), which I > presume calls BDW-GC GC_malloc_atomic(nbytes) > > So, (a) the patch below is totally useless for any srfi-4 ops, and (b) it would > probably be more interesting to address this GC Warning reports for repeated > large block of mem with a 'global' guile approach ... which I unfortunately can't > do: I just don't have the knowledge and the experience. > > I can still try to patch srfi-4.c, for fun and locally, but even that is not easy > for me, because I read and write basic C (far from expert level), and I'm quickly > lost even just reading libguile code ... > > David ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: GC Warning related to large mem block allocation - Help needed 2017-12-30 5:10 ` Mike Gran @ 2017-12-30 23:38 ` David Pirotte 2017-12-31 13:22 ` David Pirotte 0 siblings, 1 reply; 8+ messages in thread From: David Pirotte @ 2017-12-30 23:38 UTC (permalink / raw) To: Mike Gran; +Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 2550 bytes --] Hi Mike, > If all you are doing is trying to get Guile not to issue warnings about big > allocations, I think all you need to do is put -DGC_IGNORE_WARN in the > CFLAGS when you build Guile. Thanks for the suggestion, but it does not work. If I trust guile (gcc) to use an exported CFLAGS env variable: export CFLAGS="-O3 -DGC_IGNORE_WARN" [ which is properly listed in the config.log after configure... and if this flag is 'correct', it appeared to work at first glance: scheme@(guile-user)> ,use (srfi srfi-4) scheme@(guile-user)> (for-each (lambda (i) (make-f32vector 100000000)) (iota 100)) [ no warnings here but a more expensive task triggers these warnings still scheme@(guile-user)> ,time (quasep caso-9 '1mm) init... GC Warning: Repeated allocation of very large block (appr. size 775012352): May lead to memory leak and poor performance. kernels... GC Warning: Repeated allocation of very large block (appr. size 775237632): May lead to memory leak and poor performance. small pellets... GC Warning: Repeated allocation of very large block (appr. size 775012352): May lead to memory leak and poor performance. grip layer... GC Warning: Repeated allocation of very large block (appr. size 775012352): May lead to memory leak and poor performance. GC Warning: Repeated allocation of very large block (appr. size 775012352): May lead to memory leak and poor performance. micro pellets... GC Warning: Repeated allocation of very large block (appr. size 775012352): May lead to memory leak and poor performance. GC Warning: Repeated allocation of very large block (appr. size 775012352): May lead to memory leak and poor performance. gripped kernels... GC Warning: Repeated allocation of very large block (appr. size 775012352): May lead to memory leak and poor performance. GC Warning: Repeated allocation of very large block (appr. size 775012352): May lead to memory leak and poor performance. GC Warning: Repeated allocation of very large block (appr. size 775012352): May lead to memory leak and poor performance. none gripped kernels... GC Warning: Repeated allocation of very large block (appr. size 775012352): May lead to memory leak and poor performance. quase particles... GC Warning: Repeated allocation of very large block (appr. size 775012352): May lead to memory leak and poor performance. $1 = ((13755 14086 3 (#f32(255.0 255.0 255.0 255.0 255.0 255.0 255.0 # # ...) ...)) # ...) ;; 300.318682s real time, 369.596406s run time. 5.252115s spent in GC. [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: GC Warning related to large mem block allocation - Help needed 2017-12-30 23:38 ` David Pirotte @ 2017-12-31 13:22 ` David Pirotte 2018-01-01 14:11 ` Freja Nordsiek 0 siblings, 1 reply; 8+ messages in thread From: David Pirotte @ 2017-12-31 13:22 UTC (permalink / raw) To: Mike Gran; +Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 602 bytes --] Hello, > > If all you are doing is trying to get Guile not to issue warnings about big > > allocations, I think all you need to do is put -DGC_IGNORE_WARN in the > > CFLAGS when you build Guile. > Thanks for the suggestion, but it does not work. For those interested, Mike did find a way to get rid of those warnings, and posted it in #guile: <spk121> daviid: to quell BDW-GC large alloc warnings via environment variables, you can set GC_LARGE_ALLOC_WARN_INTERVAL to something much larger than its default of 5 which works perfectly, thanks Mike! David. [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: GC Warning related to large mem block allocation - Help needed 2017-12-31 13:22 ` David Pirotte @ 2018-01-01 14:11 ` Freja Nordsiek 2018-01-01 22:05 ` Daniel Llorens 0 siblings, 1 reply; 8+ messages in thread From: Freja Nordsiek @ 2018-01-01 14:11 UTC (permalink / raw) To: David Pirotte, Mike Gran; +Cc: guile-devel David Pirotte and Guile Devel, Changing GC_LARGE_ALLOC_WARN_LEVEL seems like it is the best solution to me. Looking at the suggestions to change the allocator earlier in the discussion, I decided to look more into the feasibility of that solution to see if that alternative was fixable to avoid having to change GC_LARGE_ALLOC_WARN_LEVEL. I did some digging around on https://github.com/ivmai/bdwgc and http://www.hboehm.info/gc/ and have dug around a bit inside bytevectors.c in the past. My conclusion is that while changing the allocator properly would fix the warning, it could introduce more problems. So, sadly, it seems changing GC_LARGE_ALLOC_WARN_LEVEL is the only solution. Unless my analysis is wrong (would be nice if it was because changing the allocator would help performance too). My analysis follows: The warning is thrown because large arrays can cause major performance problems for garbage collectors that work like BDWGC. They decide to keep or collect objects based on whether anything in other objects that are being kept or in the stack point to them (either at their head or somewhere in their interiors). The standard BDWGC malloc (GC_MALLOC) allocates objects that could potentially have pointers in them and thus need to be searched for pointers to other objects. Such searching can be expensive. The BDWGC atomic malloc (GC_MALLOC_ATOMIC) is basically declaring that the object does not contain pointers and thus does not need to be searched, which saves a lot of effort for the GC. But, regardless of whether the allocation is atomic (no pointers) or not, BDWGC still needs to search everything else for pointers to the objects. Structs and things like that have a pointer or two need to be declared to have pointers even if the rest is not pointers. But the rest of the data is effectively random pointers when BDWGC looks at them. Same goes for everything on the stack that is not a pointer. The larger an allocated array is, the more likely that some non-pointer data will accidentally point to its interior if it is looked at through the lens of a pointer. This is why BDWGC throws the warning when large arrays are allocated repeatedly with GC_MALLOC and GC_MALLOC_ATOMIC. There is a high probability that many of them will be kept around beyond what is required (and thus they take up RAM) due to non-pointers accidentally pointing to them, so BDWGC lets the programmer and user know. To help mitigate this, BDWGC offers GC_MALLOC_IGNORE_OFF_PAGE and GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE (note, the latter function is not mentioned on the readme on the git page but is mentioned at http://www.hboehm.info/gc/gcinterface.html) which do the same allocations, but only considers them pointed to if pointers or data BDWGC thinks might be pointers points to the first 512 bytes of the objects. Since they then look like 512 byte long objects to BDWGC for the purpose of deciding whether to keep or collect them, there is a much lower probability of them being accidentally kept a long time. There is one major catch. If one is still using the object but one's only pointer to them is pointing at somewhere after the 512 byte mark, they could get prematurely collected. Now, going to SRFI-4 vectors and R6RS bytevectors, which underneath use mostly the same code in Guile, they are allocated in make_bytevector with GC_MALLOC_ATOMIC (indirectly through SCM_GC_MALLOC_POINTERLESS) and an SCM with a pointer to the head returned by the function. In principle, that could be changed to do a size check and then use GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE if it is larger than 100 kB (note, changing it to the non-atomic version while it would get rid of the warning and make sure it doesn't get kept too long on accident, would mean that it is searched inside for pointers which could then keep other stuff on accident). The only worry then would be that it would get collected while still being used. I think most cases, this would not be a problem. However, if someone makes a new bytevector from an existing one from somewhere in the middle, it is possible that the new one would only point to the middle and not the head and thus could be collected prematurely (would need to do some more digging to see if the new one would be allocated using make_bytevector_from_buffer). Or, if someone was using C code to say take the norm of the vector (very common operation often done with BLAS) and the scheme code wasn't going to use the bytevector anymore, there might only be a pointer on the stack pointing to the current element that the C code is reading and as soon as it gets past the 512 byte mark, the bytearray might get collected while it is still being worked on which would be a disaster. So I am not sure that the allocation could be safely changed to use GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE if the bytevector is large. I do not know enough about Guile internals yet to know if typical pure scheme operations would run into problems. I think it is definitely possible that there are FFI cases where problems could be run into, which would then mean the coder has to take extra precautions to prevent collection, which could be a major problem for changing the allocation Guile 2.0.x and 2.2.x since it would be a major API change. Wouldn't be such an issue for 3.x series since the API could be changed but it would be a bit of a surprising result for people to have to worry about if using FFI. I could be wrong on this - a pointer to the head might still be kept on the stack and then there is no problem. So, it seems, that disabling the warning through GC_LARGE_ALLOC_WARN_LEVEL or some other method is the only safe solution, unless my analysis above is wrong and the allocation code could be safely changed. Freja Nordsiek On 12/31/2017 02:22 PM, David Pirotte wrote: > Hello, > >>> If all you are doing is trying to get Guile not to issue warnings about big >>> allocations, I think all you need to do is put -DGC_IGNORE_WARN in the >>> CFLAGS when you build Guile. >> Thanks for the suggestion, but it does not work. > For those interested, Mike did find a way to get rid of those warnings, and posted it > in #guile: > > <spk121> daviid: to quell BDW-GC large alloc warnings via environment > variables, you can set GC_LARGE_ALLOC_WARN_INTERVAL to something much > larger than its default of 5 > > which works perfectly, thanks Mike! > > David. > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: GC Warning related to large mem block allocation - Help needed 2018-01-01 14:11 ` Freja Nordsiek @ 2018-01-01 22:05 ` Daniel Llorens 0 siblings, 0 replies; 8+ messages in thread From: Daniel Llorens @ 2018-01-01 22:05 UTC (permalink / raw) To: Freja Nordsiek; +Cc: Andy Wingo, guile-devel, David Pirotte On 01 Jan 2018, at 15:11, Freja Nordsiek <fnordsie@posteo.net> wrote: > The only worry then would be that it would get collected while still > being used. I think most cases, this would not be a problem. However, if > someone makes a new bytevector from an existing one from somewhere in > the middle, it is possible that the new one would only point to the > middle and not the head and thus could be collected prematurely (would > need to do some more digging to see if the new one would be allocated > using make_bytevector_from_buffer). Or, if someone was using C code to > say take the norm of the vector (very common operation often done with > BLAS) and the scheme code wasn't going to use the bytevector anymore, > there might only be a pointer on the stack pointing to the current > element that the C code is reading and as soon as it gets past the 512 > byte mark, the bytearray might get collected while it is still being > worked on which would be a disaster. So I am not sure that the > allocation could be safely changed to use > GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE if the bytevector is large. I do not > know enough about Guile internals yet to know if typical pure scheme > operations would run into problems. I think it is definitely possible > that there are FFI cases where problems could be run into, which would > then mean the coder has to take extra precautions to prevent collection, > which could be a major problem for changing the allocation Guile 2.0.x > and 2.2.x since it would be a major API change. Wouldn't be such an > issue for 3.x series since the API could be changed but it would be a > bit of a surprising result for people to have to worry about if using > FFI. I could be wrong on this - a pointer to the head might still be > kept on the stack and then there is no problem. Hi Freja, thanks for these comments. I know too little about GC, but I've dug now and then in the bytevector / array code. As a user of large arrays, I'm interested in making them more usable. The primary means for indirect access to bytevectors / arrays in Guile is the array API. All array objects contain a reference to their ‘backing store’, and array handles keep a second copy of this reference, plus a pointer to the head of the backing store (not to the head of the array itself). The array API uses a get/release mechanism whose only purpose is to keep those pointers on the stack. This makes using arrays harder and I've found it annoying, so I've asked Andy about it a couple times. AFAIU, the only functions in the public API that can create a vector/bytevector object from raw memory are the scm_take_xxx series (which are used internally by pointer->bytevector). Those functions are clearly meant to be used with ‘foreign’ storage, but if one were to use them with Guile-managed storage, then I think it's understood that the user is responsible for retaining the relevant pointers. That's also how I understand the comments above make_bytevector_from_buffer. Also AFAIU, the only ways to get a pointer to bytevector storage using the public API are 1) scm_xxx_elements / scm_xxx_writable_elements, 2) the macro SCM_BYTEVECTOR_CONTENTS, or 3) the FFI function bytevector->pointer. The scm_xxx_elements functions take an array handle and enforce the get/release interface, so they should cause no issues. I think it would be fair to add a warning to the manual that the user is responsible for retaining the pointer obtained from SCM_BYTEVECTOR_CONTENTS around any calls. I think that's what the scm_remember_upto_here functions are for, although I've never had to use them myself. I've also never used SCM_BYTEVECTOR_CONTENTS directly. I'm not sure it belongs in the public API to be honest. Then bytevector->pointer uses SCM_BYTEVECTOR_CONTENTS internally, but it also keeps (SCM_BYTEVECTOR_CONTENTS(bv) + offset) in a ‘pointer_weak_refs’ table. So it seems possible for this to happen: y = make_bytevector x = bytevector->pointer(y, offset = 512+1) do_stuff_with(x /* y is collected */) either in Scheme or in C. But it would be solved if bytevector->pointer kept just SCM_BYTEVECTOR_CONTENTS(bv) instead of (SCM_BYTEVECTOR_CONTENTS(bv) + offset) in the table. I'm not sure why it keeps (... + offset). Does this make sense? So I'd be interested in trying out GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE, if this fix to bytevector->pointer makes sense and no one can point out another *concrete* situation where it would result in a GC bug. Regards Daniel ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2018-01-01 22:05 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-12-30 1:48 GC Warning related to large mem block allocation - Help needed David Pirotte 2017-12-30 2:35 ` David Pirotte 2017-12-30 4:05 ` David Pirotte 2017-12-30 5:10 ` Mike Gran 2017-12-30 23:38 ` David Pirotte 2017-12-31 13:22 ` David Pirotte 2018-01-01 14:11 ` Freja Nordsiek 2018-01-01 22:05 ` Daniel Llorens
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).