Duncan Exon Smith via llvm-dev
2016-Mar-23 04:48 UTC
[llvm-dev] [RFC] Lazy-loading of debug info metadata
> On Mar 22, 2016, at 8:04 PM, David Blaikie <dblaikie at gmail.com> wrote: > > +pcc, who had some other ideas/patch out for improving memory usage of debug info > +Reid, who's responsible for the windows/CodeView/PDB debug info which is motivating some of the ideas about changes to type emission > > So how does this relate, or not, to Peter's (pcc) work trying to reduce the DIE overhead during code gen? Are you folks chasing different memory bottlenecks? Are they both relevant (perhaps in different scenarios)?I think this is orthogonal to Peter's work, although (2) may help DIE overhead, I'm not sure. The primary goal is actually CPU speedup when lazy-loading only a very small number of functions from a module (e.g, a module that gets imported into 1000 others needs to be lazy loaded 1000 times), but I'm using the memory stats as rough guidance for which metadata exists and takes time to parse. The memory is also a problem, but the peak memory scales linearly so it's not as bad.> Baking into the IR more about types as units has pretty direct overlap with Reid/CodeView/etc - so, yeah, that'll takes ome discussion (but, as you say, it's not in your immediate plan anyway, so we can come back to that - but would be good for whoever gets there first to discuss it with the others) > >> On Tue, Mar 22, 2016 at 7:28 PM, Duncan P. N. Exon Smith <dexonsmith at apple.com> wrote: >> I have some ideas to allow the BitcodeReader to lazy-load debug info >> metadata, and wanted to air this on llvm-dev before getting too deep >> into the code. >> >> Motivation >> =========>> >> Based on some analysis Mehdi ran (ping him for details), there are three >> (related) compile-time bottlenecks we're seeing with `-flto=thin -g`: >> >> a) Reading the large number of Metadata bitcode records in the global >> metadata block. I'm talking about raw `BitStreamer` calls here. >> >> b) Creating unnecessary `DI*` instances (that aren't relevant to code). >> >> c) Emitting unnecessary `DI*` instances (that aren't relevant to code). >> >> Here is my recollection of some peak memory stats on a small testcase >> during thin-LTO, which should be a decent indicator of (b): >> >> - ~150MB: DILocation >> - ~100MB: DISubprogram >> - ~70MB: DILocalVariable >> - ~50MB: (cumulative) DIType descendents >> >> It looks, suprisingly, like types are not the primary bottleneck. >> >> There are caveats: >> >> - `DISubprogram` declarations -- member function descriptors -- are >> part of the type hierarchy. >> - Most of the type hierarchy gets uniqued at parse time. >> - As a result, these data are a poor indicator for (a). >> >> Even so, non-types are substantial. >> >> Related work >> ===========>> >> Teresa has some post-processing in-place/in-review to avoid importing >> metadata unnecessarily, but IIUC: it won't address (a) and (b), only >> (c) (maybe I'm wrong?); and it only helps -flto=thin, not other >> lazy-loaders. >> >> I heard a rumour that Eric has a grand plan to factor away the type >> hierarchy -- awesome if true -- but I think most of this is worthwhile >> regardless. >> >> Proposal >> =======>> >> Short version >> ------------- >> >> 1. Serialize metadata in Function blocks where possible. >> 2. Reverse the `DISubprogram`/`DICompileUnit` link. >> 3. Create a `METADATA_SUBPROGRAM_BLOCK`. >> >> Type-related work Eric will make unnecessary if he's fast: >> >> 4. Remove `DICompositeType`s from `retainedTypes:`, similar to (2). >> 5. Create a `METADATA_COMPOSITE_TYPE_BLOCK`, similar to (3). >> >> Long version >> ------------ >> >> 1. If a piece of metadata is referenced from only a single `Function`, >> serialize that metadata in the function's metadata block instead of >> the global metadata block. >> >> This addresses problems (a) and (b), primarily targeting >> `DILocation`s. It should pick up lots of other stuff, depending on >> how much inlining has happened. >> >> (I have a draft of the writer side, still working on the reader.) >> >> 2. Reverse the `DISubprogram`/`DICompileUnit` link (David and I have >> talked about this in the past in barely-related threads). The >> direct effect is that subprograms that are not pointed at by any >> code (!dbg attachments or @llvm.dbg.value intrinsics) get dropped. >> >> This addresses problem (c). If a consumer is only linking/loading a >> subset of a module's functions, this naturally filters subprograms >> to the relevant ones. Also, with limited inlining (and assuming >> (1)), it addresses problems (a) and (b), too. >> >> Adrian volunteered to implement this and is apparently almost ready >> to post a patch (still working on testcase update script logic I >> believe (probably other details, don't let me oversell it)). >> >> 3. Create a special `METADATA_SUBPROGRAM_BLOCK` for each `DISubprogram` >> in the global metadata block. Store the relevant `DISubprogram` and >> all of the subprogram's `DILexicalBlock`s and `DILocalVariable`s. >> The block can be lazy-loaded on an all-or-nothing basis. >> >> In combination with (2), this addresses (a) and (b) in cases that >> (1) doesn't catch. A lazy-loading module will only load the >> subprogram blocks that get referenced. >> >> (I have a basic design for this that accounts for references into >> the middle of block; I'll see what happens when I flesh it out.) >> >> I think this will solve the non-type bottlenecks. >> >> If Eric hasn't solved types by then, we can do similar things to the IR >> for the debug info type hierarchy. >> >> 4. Implement my proposal to remove the `DICompositeType` name map from >> `retainedTypes:`. >> >> http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20160125/327936.html >> >> Similar to (2) above, this will naturally filter the types that get >> linked in to the ones actually used by the code being linked. >> >> It should also allow the reader to skip records for types that have >> already been loaded in the main module. >> >> 5. Create a special `METADATA_COMPOSITE_TYPE_BLOCK`, similar to (3) but >> for composite types and their members. This avoids the raw bitcode >> reading overhead. (This is totally undesigned at this point.) >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160322/4ca33961/attachment.html>
David Blaikie via llvm-dev
2016-Mar-23 04:56 UTC
[llvm-dev] [RFC] Lazy-loading of debug info metadata
On Tue, Mar 22, 2016 at 9:48 PM, Duncan Exon Smith <dexonsmith at apple.com> wrote:> > On Mar 22, 2016, at 8:04 PM, David Blaikie <dblaikie at gmail.com> wrote: > > +pcc, who had some other ideas/patch out for improving memory usage of > debug info > +Reid, who's responsible for the windows/CodeView/PDB debug info which is > motivating some of the ideas about changes to type emission > > So how does this relate, or not, to Peter's (pcc) work trying to reduce > the DIE overhead during code gen? Are you folks chasing different memory > bottlenecks? Are they both relevant (perhaps in different scenarios)? > > > I think this is orthogonal to Peter's work, although (2) may help DIE > overhead, I'm not sure. The primary goal is actually CPU speedup when > lazy-loading only a very small number of functions from a module (e.g, a > module that gets imported into 1000 others needs to be lazy loaded 1000 > times), but I'm using the memory stats as rough guidance for which metadata > exists and takes time to parse. The memory is also a problem, but the peak > memory scales linearly so it's not as bad. >I was mostly curious why you & Peter ended up with different bottlenecks if you're both going after the same scenario. But I see you're specifically targeting /Thin/LTO whereas he's more interested in traditional LTO. So not surprising you're hitting the memory bottlenecks in modules linking, etc, but less so in CodeGen. Did you investigate much further the straight LTO memory issues before prioritizing ThinLTO? (just curious if you got LTO to something acceptable usable for your needs, if you knew what the next biggest problem was, etc - not too important though, just curious about any institutional knowledge lying around on these different axes)> > Baking into the IR more about types as units has pretty direct overlap > with Reid/CodeView/etc - so, yeah, that'll takes ome discussion (but, as > you say, it's not in your immediate plan anyway, so we can come back to > that - but would be good for whoever gets there first to discuss it with > the others) > > On Tue, Mar 22, 2016 at 7:28 PM, Duncan P. N. Exon Smith < > dexonsmith at apple.com> wrote: > >> I have some ideas to allow the BitcodeReader to lazy-load debug info >> metadata, and wanted to air this on llvm-dev before getting too deep >> into the code. >> >> Motivation >> =========>> >> Based on some analysis Mehdi ran (ping him for details), there are three >> (related) compile-time bottlenecks we're seeing with `-flto=thin -g`: >> >> a) Reading the large number of Metadata bitcode records in the global >> metadata block. I'm talking about raw `BitStreamer` calls here. >> >> b) Creating unnecessary `DI*` instances (that aren't relevant to code). >> >> c) Emitting unnecessary `DI*` instances (that aren't relevant to code). >> >> Here is my recollection of some peak memory stats on a small testcase >> during thin-LTO, which should be a decent indicator of (b): >> >> - ~150MB: DILocation >> - ~100MB: DISubprogram >> - ~70MB: DILocalVariable >> - ~50MB: (cumulative) DIType descendents >> >> It looks, suprisingly, like types are not the primary bottleneck. >> >> There are caveats: >> >> - `DISubprogram` declarations -- member function descriptors -- are >> part of the type hierarchy. >> - Most of the type hierarchy gets uniqued at parse time. >> - As a result, these data are a poor indicator for (a). >> >> Even so, non-types are substantial. >> >> Related work >> ===========>> >> Teresa has some post-processing in-place/in-review to avoid importing >> metadata unnecessarily, but IIUC: it won't address (a) and (b), only >> (c) (maybe I'm wrong?); and it only helps -flto=thin, not other >> lazy-loaders. >> >> I heard a rumour that Eric has a grand plan to factor away the type >> hierarchy -- awesome if true -- but I think most of this is worthwhile >> regardless. >> >> Proposal >> =======>> >> Short version >> ------------- >> >> 1. Serialize metadata in Function blocks where possible. >> 2. Reverse the `DISubprogram`/`DICompileUnit` link. >> 3. Create a `METADATA_SUBPROGRAM_BLOCK`. >> >> Type-related work Eric will make unnecessary if he's fast: >> >> 4. Remove `DICompositeType`s from `retainedTypes:`, similar to (2). >> 5. Create a `METADATA_COMPOSITE_TYPE_BLOCK`, similar to (3). >> >> Long version >> ------------ >> >> 1. If a piece of metadata is referenced from only a single `Function`, >> serialize that metadata in the function's metadata block instead of >> the global metadata block. >> >> This addresses problems (a) and (b), primarily targeting >> `DILocation`s. It should pick up lots of other stuff, depending on >> how much inlining has happened. >> >> (I have a draft of the writer side, still working on the reader.) >> >> 2. Reverse the `DISubprogram`/`DICompileUnit` link (David and I have >> talked about this in the past in barely-related threads). The >> direct effect is that subprograms that are not pointed at by any >> code (!dbg attachments or @llvm.dbg.value intrinsics) get dropped. >> >> This addresses problem (c). If a consumer is only linking/loading a >> subset of a module's functions, this naturally filters subprograms >> to the relevant ones. Also, with limited inlining (and assuming >> (1)), it addresses problems (a) and (b), too. >> >> Adrian volunteered to implement this and is apparently almost ready >> to post a patch (still working on testcase update script logic I >> believe (probably other details, don't let me oversell it)). >> >> 3. Create a special `METADATA_SUBPROGRAM_BLOCK` for each `DISubprogram` >> in the global metadata block. Store the relevant `DISubprogram` and >> all of the subprogram's `DILexicalBlock`s and `DILocalVariable`s. >> The block can be lazy-loaded on an all-or-nothing basis. >> >> In combination with (2), this addresses (a) and (b) in cases that >> (1) doesn't catch. A lazy-loading module will only load the >> subprogram blocks that get referenced. >> >> (I have a basic design for this that accounts for references into >> the middle of block; I'll see what happens when I flesh it out.) >> >> I think this will solve the non-type bottlenecks. >> >> If Eric hasn't solved types by then, we can do similar things to the IR >> for the debug info type hierarchy. >> >> 4. Implement my proposal to remove the `DICompositeType` name map from >> `retainedTypes:`. >> >> >> http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20160125/327936.html >> >> Similar to (2) above, this will naturally filter the types that get >> linked in to the ones actually used by the code being linked. >> >> It should also allow the reader to skip records for types that have >> already been loaded in the main module. >> >> 5. Create a special `METADATA_COMPOSITE_TYPE_BLOCK`, similar to (3) but >> for composite types and their members. This avoids the raw bitcode >> reading overhead. (This is totally undesigned at this point.) >> >> >> >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160322/676081d9/attachment-0001.html>
Mehdi Amini via llvm-dev
2016-Mar-23 05:39 UTC
[llvm-dev] [RFC] Lazy-loading of debug info metadata
> On Mar 22, 2016, at 9:56 PM, David Blaikie <dblaikie at gmail.com> wrote: > > > > On Tue, Mar 22, 2016 at 9:48 PM, Duncan Exon Smith <dexonsmith at apple.com <mailto:dexonsmith at apple.com>> wrote: > > On Mar 22, 2016, at 8:04 PM, David Blaikie <dblaikie at gmail.com <mailto:dblaikie at gmail.com>> wrote: > >> +pcc, who had some other ideas/patch out for improving memory usage of debug info >> +Reid, who's responsible for the windows/CodeView/PDB debug info which is motivating some of the ideas about changes to type emission >> >> So how does this relate, or not, to Peter's (pcc) work trying to reduce the DIE overhead during code gen? Are you folks chasing different memory bottlenecks? Are they both relevant (perhaps in different scenarios)? > > I think this is orthogonal to Peter's work, although (2) may help DIE overhead, I'm not sure. The primary goal is actually CPU speedup when lazy-loading only a very small number of functions from a module (e.g, a module that gets imported into 1000 others needs to be lazy loaded 1000 times), but I'm using the memory stats as rough guidance for which metadata exists and takes time to parse. The memory is also a problem, but the peak memory scales linearly so it's not as bad. > > I was mostly curious why you & Peter ended up with different bottlenecks if you're both going after the same scenario. But I see you're specifically targeting /Thin/LTO whereas he's more interested in traditional LTO. So not surprising you're hitting the memory bottlenecks in modules linking, etc, but less so in CodeGen.We have the same issue using ThinLTO that exist with FullLTO during CodeGen, maybe even more difficult to scale than FullLTO (more redundant work because of all the imported debug info). However by design ThinLTO partitioning helps to handle the scalability somehow, provided that we apply a few fixes. However the IR loading/linking itself is on another level worse than FullLTO here (the number of IR lazy load is ~quadratic in the number of modules instead of linear for FullLTO). So this something that needs to be addressed on top of what Peter does, and with higher priority considering the impact. Ultimately it'll need some bitcode format redesign to be really efficient, but that's not gonna happen in the short term (we aiming at a couple of weeks milestone right now).> Did you investigate much further the straight LTO memory issues before prioritizing ThinLTO? (just curious if you got LTO to something acceptable usable for your needs, if you knew what the next biggest problem was, etc - not too important though, just curious about any institutional knowledge lying around on these different axes)We'd like to have ThinLTO "good enough" to obsolete FullLTO for most use cases. So our effort are focused on ThinLTO right now. -- Mehdi> > >> Baking into the IR more about types as units has pretty direct overlap with Reid/CodeView/etc - so, yeah, that'll takes ome discussion (but, as you say, it's not in your immediate plan anyway, so we can come back to that - but would be good for whoever gets there first to discuss it with the others) >> >> On Tue, Mar 22, 2016 at 7:28 PM, Duncan P. N. Exon Smith <dexonsmith at apple.com <mailto:dexonsmith at apple.com>> wrote: >> I have some ideas to allow the BitcodeReader to lazy-load debug info >> metadata, and wanted to air this on llvm-dev before getting too deep >> into the code. >> >> Motivation >> =========>> >> Based on some analysis Mehdi ran (ping him for details), there are three >> (related) compile-time bottlenecks we're seeing with `-flto=thin -g`: >> >> a) Reading the large number of Metadata bitcode records in the global >> metadata block. I'm talking about raw `BitStreamer` calls here. >> >> b) Creating unnecessary `DI*` instances (that aren't relevant to code). >> >> c) Emitting unnecessary `DI*` instances (that aren't relevant to code). >> >> Here is my recollection of some peak memory stats on a small testcase >> during thin-LTO, which should be a decent indicator of (b): >> >> - ~150MB: DILocation >> - ~100MB: DISubprogram >> - ~70MB: DILocalVariable >> - ~50MB: (cumulative) DIType descendents >> >> It looks, suprisingly, like types are not the primary bottleneck. >> >> There are caveats: >> >> - `DISubprogram` declarations -- member function descriptors -- are >> part of the type hierarchy. >> - Most of the type hierarchy gets uniqued at parse time. >> - As a result, these data are a poor indicator for (a). >> >> Even so, non-types are substantial. >> >> Related work >> ===========>> >> Teresa has some post-processing in-place/in-review to avoid importing >> metadata unnecessarily, but IIUC: it won't address (a) and (b), only >> (c) (maybe I'm wrong?); and it only helps -flto=thin, not other >> lazy-loaders. >> >> I heard a rumour that Eric has a grand plan to factor away the type >> hierarchy -- awesome if true -- but I think most of this is worthwhile >> regardless. >> >> Proposal >> =======>> >> Short version >> ------------- >> >> 1. Serialize metadata in Function blocks where possible. >> 2. Reverse the `DISubprogram`/`DICompileUnit` link. >> 3. Create a `METADATA_SUBPROGRAM_BLOCK`. >> >> Type-related work Eric will make unnecessary if he's fast: >> >> 4. Remove `DICompositeType`s from `retainedTypes:`, similar to (2). >> 5. Create a `METADATA_COMPOSITE_TYPE_BLOCK`, similar to (3). >> >> Long version >> ------------ >> >> 1. If a piece of metadata is referenced from only a single `Function`, >> serialize that metadata in the function's metadata block instead of >> the global metadata block. >> >> This addresses problems (a) and (b), primarily targeting >> `DILocation`s. It should pick up lots of other stuff, depending on >> how much inlining has happened. >> >> (I have a draft of the writer side, still working on the reader.) >> >> 2. Reverse the `DISubprogram`/`DICompileUnit` link (David and I have >> talked about this in the past in barely-related threads). The >> direct effect is that subprograms that are not pointed at by any >> code (!dbg attachments or @llvm.dbg.value intrinsics) get dropped. >> >> This addresses problem (c). If a consumer is only linking/loading a >> subset of a module's functions, this naturally filters subprograms >> to the relevant ones. Also, with limited inlining (and assuming >> (1)), it addresses problems (a) and (b), too. >> >> Adrian volunteered to implement this and is apparently almost ready >> to post a patch (still working on testcase update script logic I >> believe (probably other details, don't let me oversell it)). >> >> 3. Create a special `METADATA_SUBPROGRAM_BLOCK` for each `DISubprogram` >> in the global metadata block. Store the relevant `DISubprogram` and >> all of the subprogram's `DILexicalBlock`s and `DILocalVariable`s. >> The block can be lazy-loaded on an all-or-nothing basis. >> >> In combination with (2), this addresses (a) and (b) in cases that >> (1) doesn't catch. A lazy-loading module will only load the >> subprogram blocks that get referenced. >> >> (I have a basic design for this that accounts for references into >> the middle of block; I'll see what happens when I flesh it out.) >> >> I think this will solve the non-type bottlenecks. >> >> If Eric hasn't solved types by then, we can do similar things to the IR >> for the debug info type hierarchy. >> >> 4. Implement my proposal to remove the `DICompositeType` name map from >> `retainedTypes:`. >> >> http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20160125/327936.html <http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20160125/327936.html> >> >> Similar to (2) above, this will naturally filter the types that get >> linked in to the ones actually used by the code being linked. >> >> It should also allow the reader to skip records for types that have >> already been loaded in the main module. >> >> 5. Create a special `METADATA_COMPOSITE_TYPE_BLOCK`, similar to (3) but >> for composite types and their members. This avoids the raw bitcode >> reading overhead. (This is totally undesigned at this point.) >> >> >> >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160322/eeaa5aba/attachment.html>