Alexey Lapshin via llvm-dev
2020-Jun-23 21:19 UTC
[llvm-dev] [Debuginfo][DWARF][LLD] Remove obsolete debug info in lld.
>On 2020-06-22, Alexey Lapshin via llvm-dev wrote: >>>> >> >Alexey> Probably we could try to make DWARF easy to parsing, trimming, rewriting so that full DWARF >>>> >> >Alexey> parsing solution would not take too much time? >>>> >> >Alexey> >>>> >> >Alexey> f.e. -debug-types-section solution uses COMDAT sections to split and deduplicate types. >>>> >> >Alexey> That solution works quite fast. It has already mentioned drawback with a big size >>>> >> >Alexey> overhead(because of section headers/type unit headers sizes). But, the fact that type units >>>> >> >Alexey> could be identified just by hash-id(without parsing type names and types hierarchies) >>>> >> >Alexey> allows the linker to reject duplications quickly. Another thing is that the linker drops >>>> >> >Alexey> duplicated COMDAT sections without any additional check. After duplications are deleted, >>>> >> >Alexey> the debug info is still consistent. >>>> >> >Alexey> There could be done DWARF aware solution working using the same two principles: >>>> >> >Alexey> 1. compare types by hash-id. >>>> >> >Alexey> 2. drop duplications without analyzing contents. >>>> >> >Alexey> >>>> >> >Alexey> If all types are put into a separate type table and have hash-id, then it would be much easier to >>>> >> >Alexey> deduplicate them. The idea demonstrated here - https://reviews.llvm.org/P8164. (It still has a >>>> >> >Alexey> questions: whether base types should be put into type table, whether references into type table >>>> >> >Alexey> should be done by DW_AT_signature or just by offset, etc.. ) While handling that separate type table >>>> >> >Alexey> the DWARF aware linker would check the only hash_id and put only one type description >>>> >> >Alexey> with the same id in the final type table. It also would allow us to solve that -flto=thin problem - >>>> >> >Alexey> http://lists.llvm.org/pipermail/llvm-dev/2020-May/141938.html (there is dsymutil example there). >>>> >> >Alexey> i.e., the case when type definition would be removed will not occur. >>>> >> >>>> >> David>I think there is scope for lower-overhead type deduplication, >>>> >> David>especially now with type units being merged into the debug_info >>>> >> David>section. Perhaps we could drop dwo_ids and use section references to >>>> >> David>refer to types & rely on the linker to keep those referenced sections >>>> >> David>alive - though section references are longer than CU-relative >>>> >> David>references. (but we need the extra length - because if the linker >>>> >> David>deduplicates a type definition - one CU may be referencing a type very >>>> >> David>far away, so the shorter reference might be inadequate) I don't think >>>> >> David>the indirection through the type hash is /super/ significant to the >>>> >> David>cost - I think it's more in the duplication of many DIEs especially >>>> >> David>for function definitions (since the type unit sig8 system only >>>> >> David>provides a way to reference the type - not its member functions, their >>>> >> David>parameters, etc - so all those DIEs get duplicated in any CU that >>>> >> David>needs to provide a definition of a member function). We could >>>> >> David>prototype cross-unit DIE references to lower the cost of that >>>> >> David>duplication, though rumor has it that constructor based type homing >>>> >> David>might provide enough value to obviate the need for type units (or at >>>> >> David>least make the overhead not worthwhile - so revisiting the overhead to >>>> >> David>reduce it might make it worthwhile again... ). >>>> >> >>>> >> David>Probably wouldn't be super hard to use LLVM's existing cross-unit DIE >>>> >> David>Referencing machinery (implemented for LTO) to refer directly to DIEs >>>> >> David>in a type unit without using the signature system... - hmm, that'd >>>> >> David>only work if your type unit DIEs were identical? /maybe/ ? Not sure >>>> >> David>how that'd work if you wanted to refer into a type unit, but the type >>>> >> David>unit got deduplicated. Might be able to rely on the linker to preserve >>>> >> David>every unique copy of the type unit that's referenced if we phrase >>>> >> David>things carefully - so if your compiler does produce exactly identical >>>> >> David>type units they get deduplicated and sec_refs refer to the uniquely >>>> >> David>preserved copy - but otherwise it preserves as many distinct copies as >>>> >> David>needed. (I don't know enough about how that works to be sure - but I >>>> >> David>know that these linkonce/inline function deduplication does seem to >>>> >> David>cause the DWARF to refer to the singular function if that function is >>>> >> David>identical, and if it isn't, then you get 0 - so there's /something/ in >>>> >> David>the linker that can adjust for deduplicating identical duplicates... ) >>>> >> >>>> >> Probably I was a bit unclear: the above idea is not for types >>>> >> (placed in COMDAT sections) deduplicated by the linker. >>>> >>>> >Yeah, I was just wondering whether it could be useful for that too. >>>> >>>> >> This idea goes in another direction than fragmenting dwarf >>>> >> using elf sections&tricks. It seems to me that the cost of fragmenting is too high. >>>> >>>> >I tend to agree - but I'm sort of leaning towards trying to use object >>>> >features as much as possible, then implementing just enough custom >>>> >handling in the linker to recoup overhead, etc. (eg: add some kind of >>>> >small header/brief description that makes it easy for the linker to >>>> >slice-and-dice - but hopefully a domain-specific such header can be a >>>> >bit more compact than the fully general ELF form) >>>> >>>> I think this indeed should be implemented and evaluated. >>>> So that various approaches could be compared. >>>> >>>> >> It is not only the sizes of structures describing fragments but also the complexity >>>> >> of tools that should be taught to work with fragmented DWARF. >>>> >> (f.e. llvm-dwarfdump applied to object file should be able to read fragmented DWARF, >>>> >> but applied to linked executable it should work with non-fragmented DWARF). >>>> >> That idea is for the tool which works the same way as dsymutil ODR. >>>> >> >>>> >> I will shortly describe the idea of making DWARF be easier processed by dsymutil/DWARFLinker: >>>> >> >>>> >> The idea is to have only one "type table" per object file(special section .debug_types_table). >>>> >> This "type table" would contain all types. >>>> >> There could be a special type of reference - type_offset - that offset points into the type table. >>>> >> Basic types could always be placed into the start of "type table" thus, offsets to basic types >>>> >> most often would be 1 byte. There also would be a special kind of reference - reference inside the type. >>>> >> Type units sig8 system - would not be used to reference types. >>>> >> >>>> >> Types deduplication is assumed to be done, not by linker mechanism for COMDAT, >>>> >> but by a tool like dsymutil. This tool would create resulting .debug_types_table by putting there >>>> >> types from source .debug_types_table-s. Only one copy of the type would be placed into the >>>> >> resulting table. All references pointing to the deleted copy would be corrected to point >>>> >> to the single copy inside "type table". (that is how dsymutil works currently) >>>> >>>> >^ that's the step that's probably a bit expensive for a general-use >>>> >tool - it implies parsing all the DWARF to find those references and >>>> >rewrite them, I think. For a high-performance solution that could be >>>> >run by the linker I think it'd be necessary to have a solution that >>>> >doesn't involve parsing all the DIEs. >>>> >>>> According to the current dsymutil processing, >>>> exactly this process is not the most time-consuming. >>>> That could be done relatively fast. >> >>>Fair enough - though I'd still imagine any solution that involves >>>parsing all the DIEs still wouldn't be fast enough (maybe an order of >>>magnitude faster than the current solution even - but that's stuill, >>>what, 6 or 7x slower than linking without the feature?) for most users >>>to consider it a good trade-off. >> >>It seems to me that even the current 6x-7x slowdown could be useful. >>Users who already use dsymutil or llvm-dwp(assuming DWARFLinker >>would be taught to work with a split dwarf) tools spend this time and, >>in some scenarios, waste disk space by inter-mediate files. >>Thus if they would use this LLD feature in its current state >>- they would still receive benefits. >> >>Speaking of performance results - LLD is a multi-thread linker; >>it handles sections in parallel. DWARFLinker generates DWARF using >>AsmPrinter which is a stream - so it could make resulting DWARF only >>continuously. It is not surprising that the parallel solution works faster. >>Making DWARFLinker truly multi-threaded would probably allow us >>to make slowdown to be at 2x-4x range. > >If it is 6x-7x slowdown (which may be optimized to 2x-4x), I wonder >whether it is a good trade-off keeping it as an in-linker pass, or >rather we should just use another utility compressing the output separately. > >If the slowdown is such a pain, I might not consider --gc-debuginfo a >readily usable feature like --gdb-index or future --debug-names (DWARF >v5 accelator table - I have a plan to add it but I am always distracted >by other priorities at hand). Considering that this breaks GNU linkers, >I will add the following lines to the build system > > if LINKER_IS_LLD && ENABLE_GC_DEBUGINFO > add -Wl,--gc-debuginfo > >I don't think this is more complex than: > > if ENABLE_GC_DEBUGINFO > set linker to a wrapper which optimizes the output like dwz > >We probably should add another -f option for specifying the linker path, >like -fld-path= https://lists.llvm.org/pipermail/cfe-dev/2020-June/065710.htmlgc-debuginfo could be done not from linker but as a standalone tool(like dsymutil,llvm-dwp), as you said. The reasons why it was suggested to do from the linker: 1. Linker already has liveness information built and object files loaded. Thus, it would be the fastest implementation if called from the linker. Otherwise, there should be created and written address map while linking, there should be generated inter-mediate debug-info files. And then, the separate tool would read that map and load object files or inter-mediate debug-info files again. So processing time would become even longer. 2. Linker already processes debug info: error reporting, --gdb-index, upcoming --debug-names. From the design point of view, it would be good to have a separate module - DWARFLinker - which implements all that functionality. So that there would not be additional separate specific linker implementation of them. Instead, already existed implementation would be called from the linker. i.e. Depending on the tasks, the linker would call either DWARFLinker.generate-gdb-index(), DWARFLinker.generate-debug-names(), DWARFLinker.gc-debuginfo(). The idea behind gc-debuginfo was not to slowdown the linking process for everybody. But to allow generation optimized debug-info for those who need it. That is the same idea as LTO. LTO slowdowns usual compilation significantly, but it creates a highly optimized code. Thank you, Alexey.>>> Anyway, I think the dsymutil approach is still valuable, and it >>> would be useful to optimize it. >>> Do you think it would be useful to make dsymutil/DWARFLinker truly multi-thread? >>> (To make dsymutil/DWARFLinker able to process each object file in a separate thread) > >>Perhaps - that I'd probably leave up to the folks who are more >>invested in dsymutil (Adrian Prantl et al). Maybe one day we'll get it >>integrated into llvm-dwp and then I'll be interested in getting as >>much performance out of it as lld - so multithreading and things would >>be on the books. > >I think improving dsymutil is a valuable thing. >Though there are several directions which might be considered >to make it more robust: > >1. support of latest DWARF - DWARF5/DWARF64... >2. implement multi-threaded execution. >3. support of split DWARF. >4. implement dsymutil for non-darwin platform. > >All of this is a massive piece of work. >Our original investment was to solve two problems: > >1. Overlapped address ranges, which is currently close to being solved. Thank you for helping with that! > >2. Size of debug info. That still becomes an issue, but we are unsure whether we are ready to > invest in solving all the above 1-4 problems and how much community interested in it. > >Thank you, Alexey. > >>> >One way to do that would be to have a CU-local type indirection table. >>> >DIEs reference local type numbers (like local address/string numbers - >>> >addrx/strx/rnglistx) and that table contains either sig8 (no linker >>> >fixups required) or the local type offsets you describe - the linker >>> >would then only need to read this type number indirection table and >>> >rewrite them to the final type numbers. >>> >>> Yes, that could be additionally done if this process would be time-consuming. >>> >>> David, thank you for all your comments and explanations. They are extremely helpful. > >>Sure thing - really appreciate your patience with all this - it's... a >>lot of moving parts. > >>- Dave > >> >> Thank you, Alexey. >> >> > sig8 hash-id would be used to compare types and to deduplicate them. >> > It would speed up the current dsymutil context analysis. >> > Types having the same hash-id could be deduplicated. >> > This would allow deduplicating a more number of types than current dsymutil. >> > Incomplete type definitions having a similar set of members are not deduplicated by dsymutil currently. >> > In this case they would have the same hash-id. >> > >> > This "type table" would take less space than current "type units" and current ODR solution. >> > >> > Above is just an idea on how to help DWARF-aware linker(based on idea removing obsolete debug info) >> > to work faster(if that is interesting). >> > >> > Alexey. >> > >> > > From: llvm-dev <llvm-dev-bounces at lists.llvm.org> On Behalf Of James Henderson via llvm-dev >> > > Sent: Wednesday, June 3, 2020 3:48 AM >> > > To: David Blaikie <dblaikie at gmail.com> >> > > Cc: llvm-dev at lists.llvm.org >> > > Subject: Re: [llvm-dev] [Debuginfo][DWARF][LLD] Remove obsolete debug info in lld. >> > > >> > > >> > > >> > > It makes me sad that the linker (via a library or otherwise) has to be "DWARF-aware" to be able to effectively handle --gc-sections, COMDATs, --icf etc for debug info, without leaving large blocks of data kicking around. >> > > >> > > >> > > >> > > The patching to -1 (or equivalent) is probably a good lightweight solution (though I'd love it if it could be done based on section type in the future rather than section name, but that's probably outside the realm of DWARF), as it requires only minimal understanding in the linker, but anything beyond that seems to be complicated logic that is mostly due to the structure of DWARF. Patching to -1 does feel a bit like a sticking plaster/band aid to patch over the issue rather than properly solving it too - there will still be debug data (potentially significant amounts in COMDAT-heavy objects) that the linker has to write and the debugger has to somehow know how to skip (even if it knows that -1 is special-case due to the standard being updated, it needs to get as far as the -1), which is all wasted effort. >> > > >> > > >> > > >> > > We've already seen from Alexey's prototyping, and from our own experiences with the Sony proprietary linker (which tried to rewrite .debug_line only) that deconstructing the DWARF so that it can be more optimally reassembled at link time is slow going, and will probably inevitably be however much effort is put into optimising it. For a start, given the current standards, it's impossible to know how to deconstruct it without having to parse vast amounts of DWARF, which is typically going to mean a lot more parsing work than the linker would normally have to deal with. Additionally, much of this parsing work is wasted effort, since it seems unlikely in many links that large amounts of the DWARF will be redundant. Having an option to opt-in doesn't help much there, since it just means the logic exists without most people using it, due to it not being good enough, or potentially they don't even know it exists. >> > > >> > > >> > > >> > > I don't have particularly concrete suggestions as to how to solve the structural problems with DWARF at this point. The only thing that seems obvious to me is a more "blessed" approach to fragmentation of sections, similar to what I tried with my prototype mentioned earlier in the thread, although we'd need to figure out the previously stated performance issues. Other ideas might tie into this, like somehow sharing the various table headers a bit like CIEs in .eh_frame that could be merged by the linker - each object could have separate table header sections, which are referenced by the individual .debug_* blocks, which in turn are one per function/data piece and easily discardable/merged by the linker. >> > > >> > > >> > > >> > > Just some thoughts. >> > > >> > > >> > > >> > > James >> > > >> > > >> > > >> > > On Tue, 2 Jun 2020 at 19:24, David Blaikie via llvm-dev <llvm-dev at lists.llvm.org> wrote: >> > > >> > > On Tue, May 19, 2020 at 7:17 AM Alexey Lapshin >> > > <alapshin at accesssoftek.com> wrote: >> > > > >> > > > Hi David, please find my comments inside: >> > > > >> > > > >> > > > >>>Broad question: Do you have any specific motivation/users/etc in implementing this (if you can speak about it)? >> > > > >> > > > >>> - it might help motivate the work, understand what tradeoffs might be suitable for you/your users, etc. >> > > > >> > > > >>There are two general requirements: >> > > > >> 1) Remove (or clean) invalid debug info. >> > > > >> > > > > >> > > > >Perhaps a simpler direct solution for your immediate needs might be a much narrower, >> > > > >and more efficient linker-DWARF-awareness feature: >> > > > > >> > > > > With DWARFv5, rnglists present an opportunity for a DWARF linker to rewrite the ranges >> > > > > without parsing the rest of the DWARF. /technically/ this isn't guaranteed - rnglist entries >> > > > > can be referenced either directly, or by index. If all rnglists are referenced by index, then >> > > > > a linker could parse only the debug_rnglists section and rewrite ranges to remove any >> > > > > address ranges that refer to optimized-out code. >> > > > > >> > > > > This would only be correct for rnglists that had no direct references to them (that only were >> > > > > referenced via the indexes) - but we could either implement it with that assumption, or could >> > > > > add an LLVM extension attribute on the CU that would say "I promise I only referenced rnglists >> > > > > via rnglistx forms/indexes). If this DWARF-aware linking would have to read the CU DIE (not >> > > > > all the other DIEs) it /could/ also then rewrite high/low_pc if the CU wasn't using ranges... >> > > > > but that wouldn't come up in the function-removal case, because then you'd have ranges anyway, >> > > > > so no need for that. >> > > > > >> > > > > Such a DWARF-aware rnglist linking could also simplify rnglists, in cases where functions >> > > > > ended up being laid out next to each other, the linker could coalesce their ranges together. >> > > > > >> > > > > I imagine this could be implemented with very little overhead to linking, especially compared >> > > > > to the overhead of full DWARF-aware linking. >> > > > > >> > > > >Though none of this fixes Split DWARF, where the linker doesn't get a chance to see the >> > > > > addresses being used - but if you only want/need the CU-level ranges to be correct, this >> > > > > might be a viable fix, and quite efficient. >> > > > >> > > > Yes, we think about that alternative. This would resolve our problem of invalid debug info >> > > > and would work much faster. Thus, if we would not have good results for D74169 then we >> > > > will implement it. Do you think it could be useful to have this solution in upstream? >> > > >> > > A pure rnglist rewriting - I think it'd be OK to have in upstream - >> > > again, cost/benefit/etc would have to be weighed. I'm not sure it >> > > would save enough space to be particularly valuable beyond the >> > > correctness issue - and it doesn't completely solve the correctness >> > > issue for zero-address usage or low-address usage (because you could >> > > still have overlapping subprograms inside a CU - so if you were >> > > symbolizing you could use the correct rnglist to filter, but then go >> > > look inside the CU only to find two subprograms that had that address >> > > & not know which one was the correct one an which one was the >> > > discarded one). >> > > >> > > rnglist rewriting might be easy enough to prototype - but depends what >> > > you want to spend your time on, I know this whole issue has been a >> > > huge investment of your time already - but maybe this recent >> > > revitalization of the conversation around having an explicit value in >> > > the linker might be sufficient to address everyone's needs... *fingers >> > > crossed*) >> > > >> > > >> > > > >> 2) Optimize the DWARF size. >> > > > >> > > > >> > > > > Do your users care much about this? I imagine if they had significant DWARF size issues, >> > > > > they'd have significant link time issues and the kind of cost to link time this feature has would >> > > > > be prohibitive - but perhaps they're sharing linked binaries much more often than they're >> > > > > actually performing linking. >> > > > >> > > > Yes, they do. They also have significant link-time issues. >> > > > So current performance results of D74169 are not very acceptable. >> > > > We hope to improve it. >> > > > >> > > > >> > > > >> > > > >>The specifics which our users have: >> > > > >> - embedded platform which uses 0 as start of .text section. >> > > > >> - custom toolset which does not support all features yet(f.e. split dwarf). >> > > > >> - tolerant of the link-time increase. >> > > > >> - need a useful way to share debug builds. >> > > > >> > > > >> > > > > Sharing two files (executable and dwp) is significantly less useful than sharing one file? >> > > > >> > > > Probably not significantly, but yes, it looks less useful comparing to D74169. >> > > > Having only two files (executable and .dwp) looks significantly better than having executable and multiple .dwo files. >> > > > Having only one file(executable) with minimal size looks better than the two files with a bigger size. >> > > > >> > > > clang compiled with -gsplitdwarf takes 0.9G for executable and 0.9G for .dwp. >> > > > clang compiled with -gc-debuginfo takes only 0.76G for single executable. >> > > > >> > > > >> > > > >> > > > >>For the first point: we have a problem "Overlapping address ranges starting from 0"(D59553). >> > > > >> > > > >>We use custom solution, but the general solution like D74169 would be better here. >> > > > >> > > > >> > > > > If CU ranges are the only ones that need fixing, then I think the above solution might be as >> > > > > good/better - if more than CU ranges need fixing, then I think we might want to start talking about >> > > > > how to fix DWARF itself (split and non-split) to signal certain addresses point to dead code with a >> > > > > specific blessed value that linkers would need to implement - because with Split DWARF there's >> > > > > no way to solve the non-CU addresses at the linker. >> > > > >> > > > I think the worthful solution for that signal value would be LowPC > HighPC. >> > > > That does not require additional bits in DWARF. >> > > > It would be natural to skip such address ranges since they explicitly marked as invalid. >> > > > It could be implemented in a linker very easily. Probably, it would make sense to describe that >> > > > usage in DWARF standard. >> > > > >> > > > As to the addresses which are not seen by the linker(since they are in .dwo files) - yes, >> > > > they need to have another solution. Could you show an example of such a case, please? >> > > > >> > > > >> > > > >> > > > >>>2. Support of type units. >> > > > >> > > > >>> >> > > > >> > > > >>>> That could be implemented further. >> > > > >> > > > >>>Enabling type units increases object size to make it easier to deduplicate at link time by a DWARF-unaware >> > > > >> > > > >>>linker. With a DWARF aware linker it'd be generally desirable not to have to add that object size overhead to >> > > > >> > > > >>>get the linking improvements. >> > > > >> > > > >> >> > > > >> > > > >>But, DWARFLinker should adequately work with type units since they are already implemented. >> > > > >> > > > >> > > > > Maybe - it'd be nice & all, but I don't think it's an outright necessity - if someone knows they're using >> > > > > a DWARF-aware linker, they'd probably not use type units in their object files. It's possible someone >> > > > > doesn't know for sure & maybe they have pre-canned debug object files from someone else, etc. >> > > > >> > > > I see. >> > > > >> > > > >>Another thing is that the idea behind type units has the potential to help Dwarf-aware linker to work faster. >> > > > >> > > > >>Currently, DWARFLinker analyzes context to understand whether types are the same or not. >> > > > >> > > > >> > > > >When you say "analyzes context" what do you mean? Usually I'd take that to mean >> > > > > "looks at things outside the type itself - like what namespace it's in, etc" - which, yes, >> > > > > it should do that, but it doesn't seem very expensive to do. But I guess you actually >> > > > > mean something about doing structural equivalence in some way, looking at things inside the type? >> > > > >> > > > I think it could be useful for both cases. Currently, dsymutil does only first thing >> > > > (look at type name, namespace name, etc..) and does not do the second thing >> > > > (doing structural equivalence). Analyzing type names is currently quite expensive >> > > > (the only search in string pool takes ~10 sec from 70 sec of overall time). >> > > > That is expensive because of many things should be done to work with strings: >> > > > parse DWARF, search and resolve relocations, compute a hash for strings, >> > > > put data into a string pool, create a fully qualified name(like namespace::function::name). >> > > > It looks like it could be optimized and finally require less time, but it still would be a noticeable >> > > > part of the overall time. >> > > > >> > > > If dsymutil starts to check for the structural equivalence, then the process would be even more slowly. >> > > > So, If instead of comparing types structure, there would be checked single hash-id - then this process >> > > > would also be faster. >> > > > >> > > > Thus I think using hash-id to compare types would allow to make current implementation faster and would >> > > > allow handling incomplete types by DWARFLinker without massive performance degradation also. >> > > > >> > > > >> But the context is known when types are generated. So, no need to spent the time analyzing it. >> > > > >> > > > >> If types could be compared without analyzing context, then Dwarf-aware linker would work faster. >> > > > >> > > > >> That is just an idea(not for immediate implementation): If types would be stored in some "type table" >> > > > >> > > > >> (instead of COMDAT section group) and could be accessed through hash-id(like type units >> > > > >> > > > >> - then it would be the solution requiring fewer bits to store but allowing to compare types >> > > > >> > > > >> by hash-id(not analysing context). >> > > > >> In this case, size increasing would be small. And processing time could be done faster. >> > > > >> >> > > > >> this is just an idea and could be discussed separately from the problem of integrating of D74169. >> > > > >> > > > >> >> 6. -flto=thin >> > > > >> > > > >> >> That problem was described in this review https://reviews.llvm.org/D54747#1503720. It also exists in >> > > > >> > > > >> >> current DWARFLinker/dsymutil implementation. I think that problem should be discussed more: it could >> > > > >> > > > >> >> probably be fixed by avoiding generation of such incomplete declaration during thinlto, >> > > > >> > > > >> >> That would be costly to produce extra/redundant debug info in ThinLTO - actually ThinLTO could be doing >> > > > >> > > > >> >> more to reduce that redundancy early on (actually removing definitions from some llvm Modules if the type >> > > > >> > > > >> >> definition is known to exist in another Module, etc) >> > > > >> >I don't know if it's a problem since that patch was reverted. >> > > > >> > > > >> >> > > > >> > > > >> Yes. That patch was reverted, but this patch(D74169) has the same problem. >> > > > >> > > > >> if D74169 would be applied and --gc-debuginfo used then structure type >> > > > >> definition would be removed. >> > > > >> > > > >> DWARFLinker could handle that case - "removing definitions from some llvm Modules if the type >> > > > >> definition is known to exist in another Module". >> > > > >> i.e. DWARFLinker could replace the declaration with the definition. >> > > > >> > > > >> But that problem could be more easily resolved when debug info is generated(probably without >> > > > >> significant increase of debug info size): >> > > > >> > > > >> Here we have: >> > > > >> > > > >> DW_TAG_compile_unit(0x0000000b) - compile unit containing concrete instance for function "f". >> > > > >> DW_TAG_compile_unit(0x00000073) - compile unit containing abstract instance root for function "f". >> > > > >> DW_TAG_compile_unit(0x000000c1) - compile unit containing function "f" definition. >> > > > >> > > > >> Code for function "f" was deleted. gc-debuginfo deletes compile unit DW_TAG_compile_unit(0x000000c1) >> > > > >> containing "f" definition (since there is no corresponding code). But it has structure "Foo" definition >> > > > >> DW_TAG_structure_type(0x0000011e) referenced from DW_TAG_compile_unit(0x00000073) >> > > > >> by declaration DW_TAG_structure_type(0x000000ae). That declaration is exactly the case when definition >> > > > >> was removed by thinlto and replaced with declaration. >> > > > >> > > > >> Would it cost too much if type definition would not be replaced with declaration for "abstract instance root"? >> > > > >> The number of concrete instances is bigger than number of abstract instance roots. >> > > > >> Probably, it would not be too costly to leave definition in abstract instance root? >> > > > >> > > > >> > > > >> > > > >> Alternatively, Would it cost too much if type definition would not be replaced with declaration when >> > > > >> declaration references type from not used function? (lto could understand that concrete function is not used). >> > > > >> > > > >> > > > >I don't follow this example - could you provide a small concrete test case I could reproduce? >> > > > >> > > > I would provide a test case if necessary. But it looks like this issue is finally clear, and you already commented on that. >> > > > >> > > > > Oh, I guess this is happening perhaps because ThinLTO can't know for sure that a standalone >> > > > > definition of 'f' won't be needed - so it produces one in case one of the inlining opportunities >> > > > > doesn't end up inlining. Then it turns out all calls got inlined, so the external definition wasn't needed. >> > > > >> > > > > Oh, you're suggesting that these 3 CUs got emitted into one object file during LTO, but that DWARFLinker >> > > > > drops a CU without any code in it - even though... So far as I know, in LTO, LLVM directly references >> > > > > types across units if the CUs are all emitted in the same object file. (and if they weren't in the same >> > > > > object file - then the abstract_origin couldn't be pointing cross-CU). >> > > > >> > > > > I guess some basic things to say: >> > > > >> > > > > With ThinLTO, the concrete/standalone function definition is emitted in case some call sites don't end up >> > > > > being inlined. So we know it'll be emitted (but might not be needed by the actual linker) >> > > > > ANy number of inline calls might exist - but we shouldn't put the type information into those, because >> > > > > they aren't guaranteed to emit it (if the inline function gets optimized away, there would be nothing to >> > > > > enforce the type being emitted) - and even if we forced the type information to be emitted into one >> > > > > object file that has an inline copy of the function - there's no guarantee that object file will get linked in either. >> > > > >> > > > > So, no, I don't think there's much we can do to keep the size of object files down, while guaranteeing >> > > > > the type information will be emitted with the usual linker semantics. >> > > > >> > > > Then dsymutil/DWARFLinker could be changed to handle that(though it would probably be not very efficient). >> > > > If thinlto would understand that function is not used finally(and then must not contain referenced type definition), >> > > > then this situation could be handled more effectively. >> > > > >> > > > Thank you, Alexey. >> > > > >> > > >>> >> > > >>> >> > > >>> >> > > >>> >> > > >>> _______________________________________________ >> > > >>> LLVM Developers mailing list >> > > >>> llvm-dev at lists.llvm.org >> > > >>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >> > > _______________________________________________ >> > > LLVM Developers mailing list >> > > llvm-dev at lists.llvm.org >> > > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >_______________________________________________ >LLVM Developers mailing list >llvm-dev at lists.llvm.org >https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
David Blaikie via llvm-dev
2020-Jun-23 21:31 UTC
[llvm-dev] [Debuginfo][DWARF][LLD] Remove obsolete debug info in lld.
On Tue, Jun 23, 2020 at 2:19 PM Alexey Lapshin <alapshin at accesssoftek.com> wrote:> > >On 2020-06-22, Alexey Lapshin via llvm-dev wrote: > >>>> >> >Alexey> Probably we could try to make DWARF easy to parsing, trimming, rewriting so that full DWARF > >>>> >> >Alexey> parsing solution would not take too much time? > >>>> >> >Alexey> > >>>> >> >Alexey> f.e. -debug-types-section solution uses COMDAT sections to split and deduplicate types. > >>>> >> >Alexey> That solution works quite fast. It has already mentioned drawback with a big size > >>>> >> >Alexey> overhead(because of section headers/type unit headers sizes). But, the fact that type units > >>>> >> >Alexey> could be identified just by hash-id(without parsing type names and types hierarchies) > >>>> >> >Alexey> allows the linker to reject duplications quickly. Another thing is that the linker drops > >>>> >> >Alexey> duplicated COMDAT sections without any additional check. After duplications are deleted, > >>>> >> >Alexey> the debug info is still consistent. > >>>> >> >Alexey> There could be done DWARF aware solution working using the same two principles: > >>>> >> >Alexey> 1. compare types by hash-id. > >>>> >> >Alexey> 2. drop duplications without analyzing contents. > >>>> >> >Alexey> > >>>> >> >Alexey> If all types are put into a separate type table and have hash-id, then it would be much easier to > >>>> >> >Alexey> deduplicate them. The idea demonstrated here - https://reviews.llvm.org/P8164. (It still has a > >>>> >> >Alexey> questions: whether base types should be put into type table, whether references into type table > >>>> >> >Alexey> should be done by DW_AT_signature or just by offset, etc.. ) While handling that separate type table > >>>> >> >Alexey> the DWARF aware linker would check the only hash_id and put only one type description > >>>> >> >Alexey> with the same id in the final type table. It also would allow us to solve that -flto=thin problem - > >>>> >> >Alexey> http://lists.llvm.org/pipermail/llvm-dev/2020-May/141938.html (there is dsymutil example there). > >>>> >> >Alexey> i.e., the case when type definition would be removed will not occur. > >>>> >> > >>>> >> David>I think there is scope for lower-overhead type deduplication, > >>>> >> David>especially now with type units being merged into the debug_info > >>>> >> David>section. Perhaps we could drop dwo_ids and use section references to > >>>> >> David>refer to types & rely on the linker to keep those referenced sections > >>>> >> David>alive - though section references are longer than CU-relative > >>>> >> David>references. (but we need the extra length - because if the linker > >>>> >> David>deduplicates a type definition - one CU may be referencing a type very > >>>> >> David>far away, so the shorter reference might be inadequate) I don't think > >>>> >> David>the indirection through the type hash is /super/ significant to the > >>>> >> David>cost - I think it's more in the duplication of many DIEs especially > >>>> >> David>for function definitions (since the type unit sig8 system only > >>>> >> David>provides a way to reference the type - not its member functions, their > >>>> >> David>parameters, etc - so all those DIEs get duplicated in any CU that > >>>> >> David>needs to provide a definition of a member function). We could > >>>> >> David>prototype cross-unit DIE references to lower the cost of that > >>>> >> David>duplication, though rumor has it that constructor based type homing > >>>> >> David>might provide enough value to obviate the need for type units (or at > >>>> >> David>least make the overhead not worthwhile - so revisiting the overhead to > >>>> >> David>reduce it might make it worthwhile again... ). > >>>> >> > >>>> >> David>Probably wouldn't be super hard to use LLVM's existing cross-unit DIE > >>>> >> David>Referencing machinery (implemented for LTO) to refer directly to DIEs > >>>> >> David>in a type unit without using the signature system... - hmm, that'd > >>>> >> David>only work if your type unit DIEs were identical? /maybe/ ? Not sure > >>>> >> David>how that'd work if you wanted to refer into a type unit, but the type > >>>> >> David>unit got deduplicated. Might be able to rely on the linker to preserve > >>>> >> David>every unique copy of the type unit that's referenced if we phrase > >>>> >> David>things carefully - so if your compiler does produce exactly identical > >>>> >> David>type units they get deduplicated and sec_refs refer to the uniquely > >>>> >> David>preserved copy - but otherwise it preserves as many distinct copies as > >>>> >> David>needed. (I don't know enough about how that works to be sure - but I > >>>> >> David>know that these linkonce/inline function deduplication does seem to > >>>> >> David>cause the DWARF to refer to the singular function if that function is > >>>> >> David>identical, and if it isn't, then you get 0 - so there's /something/ in > >>>> >> David>the linker that can adjust for deduplicating identical duplicates... ) > >>>> >> > >>>> >> Probably I was a bit unclear: the above idea is not for types > >>>> >> (placed in COMDAT sections) deduplicated by the linker. > >>>> > >>>> >Yeah, I was just wondering whether it could be useful for that too. > >>>> > >>>> >> This idea goes in another direction than fragmenting dwarf > >>>> >> using elf sections&tricks. It seems to me that the cost of fragmenting is too high. > >>>> > >>>> >I tend to agree - but I'm sort of leaning towards trying to use object > >>>> >features as much as possible, then implementing just enough custom > >>>> >handling in the linker to recoup overhead, etc. (eg: add some kind of > >>>> >small header/brief description that makes it easy for the linker to > >>>> >slice-and-dice - but hopefully a domain-specific such header can be a > >>>> >bit more compact than the fully general ELF form) > >>>> > >>>> I think this indeed should be implemented and evaluated. > >>>> So that various approaches could be compared. > >>>> > >>>> >> It is not only the sizes of structures describing fragments but also the complexity > >>>> >> of tools that should be taught to work with fragmented DWARF. > >>>> >> (f.e. llvm-dwarfdump applied to object file should be able to read fragmented DWARF, > >>>> >> but applied to linked executable it should work with non-fragmented DWARF). > >>>> >> That idea is for the tool which works the same way as dsymutil ODR. > >>>> >> > >>>> >> I will shortly describe the idea of making DWARF be easier processed by dsymutil/DWARFLinker: > >>>> >> > >>>> >> The idea is to have only one "type table" per object file(special section .debug_types_table). > >>>> >> This "type table" would contain all types. > >>>> >> There could be a special type of reference - type_offset - that offset points into the type table. > >>>> >> Basic types could always be placed into the start of "type table" thus, offsets to basic types > >>>> >> most often would be 1 byte. There also would be a special kind of reference - reference inside the type. > >>>> >> Type units sig8 system - would not be used to reference types. > >>>> >> > >>>> >> Types deduplication is assumed to be done, not by linker mechanism for COMDAT, > >>>> >> but by a tool like dsymutil. This tool would create resulting .debug_types_table by putting there > >>>> >> types from source .debug_types_table-s. Only one copy of the type would be placed into the > >>>> >> resulting table. All references pointing to the deleted copy would be corrected to point > >>>> >> to the single copy inside "type table". (that is how dsymutil works currently) > >>>> > >>>> >^ that's the step that's probably a bit expensive for a general-use > >>>> >tool - it implies parsing all the DWARF to find those references and > >>>> >rewrite them, I think. For a high-performance solution that could be > >>>> >run by the linker I think it'd be necessary to have a solution that > >>>> >doesn't involve parsing all the DIEs. > >>>> > >>>> According to the current dsymutil processing, > >>>> exactly this process is not the most time-consuming. > >>>> That could be done relatively fast. > >> > >>>Fair enough - though I'd still imagine any solution that involves > >>>parsing all the DIEs still wouldn't be fast enough (maybe an order of > >>>magnitude faster than the current solution even - but that's stuill, > >>>what, 6 or 7x slower than linking without the feature?) for most users > >>>to consider it a good trade-off. > >> > >>It seems to me that even the current 6x-7x slowdown could be useful. > >>Users who already use dsymutil or llvm-dwp(assuming DWARFLinker > >>would be taught to work with a split dwarf) tools spend this time and, > >>in some scenarios, waste disk space by inter-mediate files. > >>Thus if they would use this LLD feature in its current state > >>- they would still receive benefits. > >> > >>Speaking of performance results - LLD is a multi-thread linker; > >>it handles sections in parallel. DWARFLinker generates DWARF using > >>AsmPrinter which is a stream - so it could make resulting DWARF only > >>continuously. It is not surprising that the parallel solution works faster. > >>Making DWARFLinker truly multi-threaded would probably allow us > >>to make slowdown to be at 2x-4x range. > > > >If it is 6x-7x slowdown (which may be optimized to 2x-4x), I wonder > >whether it is a good trade-off keeping it as an in-linker pass, or > >rather we should just use another utility compressing the output separately. > > > >If the slowdown is such a pain, I might not consider --gc-debuginfo a > >readily usable feature like --gdb-index or future --debug-names (DWARF > >v5 accelator table - I have a plan to add it but I am always distracted > >by other priorities at hand). Considering that this breaks GNU linkers, > >I will add the following lines to the build system > > > > if LINKER_IS_LLD && ENABLE_GC_DEBUGINFO > > add -Wl,--gc-debuginfo > > > >I don't think this is more complex than: > > > > if ENABLE_GC_DEBUGINFO > > set linker to a wrapper which optimizes the output like dwz > > > >We probably should add another -f option for specifying the linker path, > >like -fld-path= https://lists.llvm.org/pipermail/cfe-dev/2020-June/065710.html > > gc-debuginfo could be done not from linker but as a standalone > tool(like dsymutil,llvm-dwp), as you said. The reasons why it > was suggested to do from the linker: > > 1. Linker already has liveness information built and object files loaded. > Thus, it would be the fastest implementation if called from the linker. > Otherwise, there should be created and written address map while > linking, there should be generated inter-mediate debug-info files. > And then, the separate tool would read that map and load object files > or inter-mediate debug-info files again. So processing time > would become even longer.I think the suggestion would be to link as normal, then process to optimize (like dwz - I believe it does something like this too). It wouldn't need a map from the linker - it could use the existing tombstone values in the linked DWARF to determine what to drop. Yes, the processing time would be longer, for sure. (I think Fangrui's suggestion there is "if you're willing to take a (let's say optimized) 2x or more increase to link time, maybe (let's say doing the intermediate step adds some fairly significant chunk of overhead) 3x wouldn't make too much of a difference?)> 2. Linker already processes debug info: error reporting,It's important that it's only consulted in the error path - if the link is failing anyway, taking a little longer to fail isn't likely to significantly hurt the user experience (compared to the time it takes a human to read the message, process it/think about what it means and come up with a theory about how to address it). Compared to getting in the way of the automated path to a working executable.> --gdb-index, > upcoming --debug-names.Importantly, these can be produced without parsing a lot of DWARF if the input contains gnu_pubnames, or debug_names (yeah, currently gdb_index still is quite costly (but I think more like 10s of percent in link time, not multiple 100s of percent) in memory and link time even when it's only parsing gnu_pubnames.> From the design point of view, it would be > good to have a separate module - DWARFLinker - which implements > all that functionality. So that there would not be additional separate > specific linker implementation of them. Instead, already existed > implementation would be called from the linker. i.e. Depending on the > tasks, the linker would call either DWARFLinker.generate-gdb-index(), > DWARFLinker.generate-debug-names(), DWARFLinker.gc-debuginfo(). > > The idea behind gc-debuginfo was not to slowdown the linking process for everybody. > But to allow generation optimized debug-info for those who need it. > That is the same idea as LTO. LTO slowdowns usual compilation significantly, > but it creates a highly optimized code.Yep - I think the main difference there is going to be the size of the user base compared to the complexity (certainly LTO adds complexity to the linker - though without much alternative (well, alternative would be build systems being aware of this - sort of like Fangrui's suggestion, LTO could be a separate tool that merges LLVM bitcode files, then creates real object files that go to the actual native linker) to gain the desired performance). Fangrui: What's your assessment of the complexity of adding this functionality to lld? Are you concerned it'll be an ongoing maintenance burden on other work in lld? If not, I'd be inclined to/lean towards accepting this & having some room for Alexey to improve the performance for his own users needs (& hopefully that'll improve DWARFLinker functionality/performance as well), see if anyone else wants this link time tradeoff. - Dave> > Thank you, Alexey. > > >>> Anyway, I think the dsymutil approach is still valuable, and it > >>> would be useful to optimize it. > >>> Do you think it would be useful to make dsymutil/DWARFLinker truly multi-thread? > >>> (To make dsymutil/DWARFLinker able to process each object file in a separate thread) > > > >>Perhaps - that I'd probably leave up to the folks who are more > >>invested in dsymutil (Adrian Prantl et al). Maybe one day we'll get it > >>integrated into llvm-dwp and then I'll be interested in getting as > >>much performance out of it as lld - so multithreading and things would > >>be on the books. > > > >I think improving dsymutil is a valuable thing. > >Though there are several directions which might be considered > >to make it more robust: > > > >1. support of latest DWARF - DWARF5/DWARF64... > >2. implement multi-threaded execution. > >3. support of split DWARF. > >4. implement dsymutil for non-darwin platform. > > > >All of this is a massive piece of work. > >Our original investment was to solve two problems: > > > >1. Overlapped address ranges, which is currently close to being solved. Thank you for helping with that! > > > >2. Size of debug info. That still becomes an issue, but we are unsure whether we are ready to > > invest in solving all the above 1-4 problems and how much community interested in it. > > > >Thank you, Alexey. > > > >>> >One way to do that would be to have a CU-local type indirection table. > >>> >DIEs reference local type numbers (like local address/string numbers - > >>> >addrx/strx/rnglistx) and that table contains either sig8 (no linker > >>> >fixups required) or the local type offsets you describe - the linker > >>> >would then only need to read this type number indirection table and > >>> >rewrite them to the final type numbers. > >>> > >>> Yes, that could be additionally done if this process would be time-consuming. > >>> > >>> David, thank you for all your comments and explanations. They are extremely helpful. > > > >>Sure thing - really appreciate your patience with all this - it's... a > >>lot of moving parts. > > > >>- Dave > > > >> > >> Thank you, Alexey. > >> > >> > sig8 hash-id would be used to compare types and to deduplicate them. > >> > It would speed up the current dsymutil context analysis. > >> > Types having the same hash-id could be deduplicated. > >> > This would allow deduplicating a more number of types than current dsymutil. > >> > Incomplete type definitions having a similar set of members are not deduplicated by dsymutil currently. > >> > In this case they would have the same hash-id. > >> > > >> > This "type table" would take less space than current "type units" and current ODR solution. > >> > > >> > Above is just an idea on how to help DWARF-aware linker(based on idea removing obsolete debug info) > >> > to work faster(if that is interesting). > >> > > >> > Alexey. > >> > > >> > > From: llvm-dev <llvm-dev-bounces at lists.llvm.org> On Behalf Of James Henderson via llvm-dev > >> > > Sent: Wednesday, June 3, 2020 3:48 AM > >> > > To: David Blaikie <dblaikie at gmail.com> > >> > > Cc: llvm-dev at lists.llvm.org > >> > > Subject: Re: [llvm-dev] [Debuginfo][DWARF][LLD] Remove obsolete debug info in lld. > >> > > > >> > > > >> > > > >> > > It makes me sad that the linker (via a library or otherwise) has to be "DWARF-aware" to be able to effectively handle --gc-sections, COMDATs, --icf etc for debug info, without leaving large blocks of data kicking around. > >> > > > >> > > > >> > > > >> > > The patching to -1 (or equivalent) is probably a good lightweight solution (though I'd love it if it could be done based on section type in the future rather than section name, but that's probably outside the realm of DWARF), as it requires only minimal understanding in the linker, but anything beyond that seems to be complicated logic that is mostly due to the structure of DWARF. Patching to -1 does feel a bit like a sticking plaster/band aid to patch over the issue rather than properly solving it too - there will still be debug data (potentially significant amounts in COMDAT-heavy objects) that the linker has to write and the debugger has to somehow know how to skip (even if it knows that -1 is special-case due to the standard being updated, it needs to get as far as the -1), which is all wasted effort. > >> > > > >> > > > >> > > > >> > > We've already seen from Alexey's prototyping, and from our own experiences with the Sony proprietary linker (which tried to rewrite .debug_line only) that deconstructing the DWARF so that it can be more optimally reassembled at link time is slow going, and will probably inevitably be however much effort is put into optimising it. For a start, given the current standards, it's impossible to know how to deconstruct it without having to parse vast amounts of DWARF, which is typically going to mean a lot more parsing work than the linker would normally have to deal with. Additionally, much of this parsing work is wasted effort, since it seems unlikely in many links that large amounts of the DWARF will be redundant. Having an option to opt-in doesn't help much there, since it just means the logic exists without most people using it, due to it not being good enough, or potentially they don't even know it exists. > >> > > > >> > > > >> > > > >> > > I don't have particularly concrete suggestions as to how to solve the structural problems with DWARF at this point. The only thing that seems obvious to me is a more "blessed" approach to fragmentation of sections, similar to what I tried with my prototype mentioned earlier in the thread, although we'd need to figure out the previously stated performance issues. Other ideas might tie into this, like somehow sharing the various table headers a bit like CIEs in .eh_frame that could be merged by the linker - each object could have separate table header sections, which are referenced by the individual .debug_* blocks, which in turn are one per function/data piece and easily discardable/merged by the linker. > >> > > > >> > > > >> > > > >> > > Just some thoughts. > >> > > > >> > > > >> > > > >> > > James > >> > > > >> > > > >> > > > >> > > On Tue, 2 Jun 2020 at 19:24, David Blaikie via llvm-dev <llvm-dev at lists.llvm.org> wrote: > >> > > > >> > > On Tue, May 19, 2020 at 7:17 AM Alexey Lapshin > >> > > <alapshin at accesssoftek.com> wrote: > >> > > > > >> > > > Hi David, please find my comments inside: > >> > > > > >> > > > > >> > > > >>>Broad question: Do you have any specific motivation/users/etc in implementing this (if you can speak about it)? > >> > > > > >> > > > >>> - it might help motivate the work, understand what tradeoffs might be suitable for you/your users, etc. > >> > > > > >> > > > >>There are two general requirements: > >> > > > >> 1) Remove (or clean) invalid debug info. > >> > > > > >> > > > > > >> > > > >Perhaps a simpler direct solution for your immediate needs might be a much narrower, > >> > > > >and more efficient linker-DWARF-awareness feature: > >> > > > > > >> > > > > With DWARFv5, rnglists present an opportunity for a DWARF linker to rewrite the ranges > >> > > > > without parsing the rest of the DWARF. /technically/ this isn't guaranteed - rnglist entries > >> > > > > can be referenced either directly, or by index. If all rnglists are referenced by index, then > >> > > > > a linker could parse only the debug_rnglists section and rewrite ranges to remove any > >> > > > > address ranges that refer to optimized-out code. > >> > > > > > >> > > > > This would only be correct for rnglists that had no direct references to them (that only were > >> > > > > referenced via the indexes) - but we could either implement it with that assumption, or could > >> > > > > add an LLVM extension attribute on the CU that would say "I promise I only referenced rnglists > >> > > > > via rnglistx forms/indexes). If this DWARF-aware linking would have to read the CU DIE (not > >> > > > > all the other DIEs) it /could/ also then rewrite high/low_pc if the CU wasn't using ranges... > >> > > > > but that wouldn't come up in the function-removal case, because then you'd have ranges anyway, > >> > > > > so no need for that. > >> > > > > > >> > > > > Such a DWARF-aware rnglist linking could also simplify rnglists, in cases where functions > >> > > > > ended up being laid out next to each other, the linker could coalesce their ranges together. > >> > > > > > >> > > > > I imagine this could be implemented with very little overhead to linking, especially compared > >> > > > > to the overhead of full DWARF-aware linking. > >> > > > > > >> > > > >Though none of this fixes Split DWARF, where the linker doesn't get a chance to see the > >> > > > > addresses being used - but if you only want/need the CU-level ranges to be correct, this > >> > > > > might be a viable fix, and quite efficient. > >> > > > > >> > > > Yes, we think about that alternative. This would resolve our problem of invalid debug info > >> > > > and would work much faster. Thus, if we would not have good results for D74169 then we > >> > > > will implement it. Do you think it could be useful to have this solution in upstream? > >> > > > >> > > A pure rnglist rewriting - I think it'd be OK to have in upstream - > >> > > again, cost/benefit/etc would have to be weighed. I'm not sure it > >> > > would save enough space to be particularly valuable beyond the > >> > > correctness issue - and it doesn't completely solve the correctness > >> > > issue for zero-address usage or low-address usage (because you could > >> > > still have overlapping subprograms inside a CU - so if you were > >> > > symbolizing you could use the correct rnglist to filter, but then go > >> > > look inside the CU only to find two subprograms that had that address > >> > > & not know which one was the correct one an which one was the > >> > > discarded one). > >> > > > >> > > rnglist rewriting might be easy enough to prototype - but depends what > >> > > you want to spend your time on, I know this whole issue has been a > >> > > huge investment of your time already - but maybe this recent > >> > > revitalization of the conversation around having an explicit value in > >> > > the linker might be sufficient to address everyone's needs... *fingers > >> > > crossed*) > >> > > > >> > > > >> > > > >> 2) Optimize the DWARF size. > >> > > > > >> > > > > >> > > > > Do your users care much about this? I imagine if they had significant DWARF size issues, > >> > > > > they'd have significant link time issues and the kind of cost to link time this feature has would > >> > > > > be prohibitive - but perhaps they're sharing linked binaries much more often than they're > >> > > > > actually performing linking. > >> > > > > >> > > > Yes, they do. They also have significant link-time issues. > >> > > > So current performance results of D74169 are not very acceptable. > >> > > > We hope to improve it. > >> > > > > >> > > > > >> > > > > >> > > > >>The specifics which our users have: > >> > > > >> - embedded platform which uses 0 as start of .text section. > >> > > > >> - custom toolset which does not support all features yet(f.e. split dwarf). > >> > > > >> - tolerant of the link-time increase. > >> > > > >> - need a useful way to share debug builds. > >> > > > > >> > > > > >> > > > > Sharing two files (executable and dwp) is significantly less useful than sharing one file? > >> > > > > >> > > > Probably not significantly, but yes, it looks less useful comparing to D74169. > >> > > > Having only two files (executable and .dwp) looks significantly better than having executable and multiple .dwo files. > >> > > > Having only one file(executable) with minimal size looks better than the two files with a bigger size. > >> > > > > >> > > > clang compiled with -gsplitdwarf takes 0.9G for executable and 0.9G for .dwp. > >> > > > clang compiled with -gc-debuginfo takes only 0.76G for single executable. > >> > > > > >> > > > > >> > > > > >> > > > >>For the first point: we have a problem "Overlapping address ranges starting from 0"(D59553). > >> > > > > >> > > > >>We use custom solution, but the general solution like D74169 would be better here. > >> > > > > >> > > > > >> > > > > If CU ranges are the only ones that need fixing, then I think the above solution might be as > >> > > > > good/better - if more than CU ranges need fixing, then I think we might want to start talking about > >> > > > > how to fix DWARF itself (split and non-split) to signal certain addresses point to dead code with a > >> > > > > specific blessed value that linkers would need to implement - because with Split DWARF there's > >> > > > > no way to solve the non-CU addresses at the linker. > >> > > > > >> > > > I think the worthful solution for that signal value would be LowPC > HighPC. > >> > > > That does not require additional bits in DWARF. > >> > > > It would be natural to skip such address ranges since they explicitly marked as invalid. > >> > > > It could be implemented in a linker very easily. Probably, it would make sense to describe that > >> > > > usage in DWARF standard. > >> > > > > >> > > > As to the addresses which are not seen by the linker(since they are in .dwo files) - yes, > >> > > > they need to have another solution. Could you show an example of such a case, please? > >> > > > > >> > > > > >> > > > > >> > > > >>>2. Support of type units. > >> > > > > >> > > > >>> > >> > > > > >> > > > >>>> That could be implemented further. > >> > > > > >> > > > >>>Enabling type units increases object size to make it easier to deduplicate at link time by a DWARF-unaware > >> > > > > >> > > > >>>linker. With a DWARF aware linker it'd be generally desirable not to have to add that object size overhead to > >> > > > > >> > > > >>>get the linking improvements. > >> > > > > >> > > > >> > >> > > > > >> > > > >>But, DWARFLinker should adequately work with type units since they are already implemented. > >> > > > > >> > > > > >> > > > > Maybe - it'd be nice & all, but I don't think it's an outright necessity - if someone knows they're using > >> > > > > a DWARF-aware linker, they'd probably not use type units in their object files. It's possible someone > >> > > > > doesn't know for sure & maybe they have pre-canned debug object files from someone else, etc. > >> > > > > >> > > > I see. > >> > > > > >> > > > >>Another thing is that the idea behind type units has the potential to help Dwarf-aware linker to work faster. > >> > > > > >> > > > >>Currently, DWARFLinker analyzes context to understand whether types are the same or not. > >> > > > > >> > > > > >> > > > >When you say "analyzes context" what do you mean? Usually I'd take that to mean > >> > > > > "looks at things outside the type itself - like what namespace it's in, etc" - which, yes, > >> > > > > it should do that, but it doesn't seem very expensive to do. But I guess you actually > >> > > > > mean something about doing structural equivalence in some way, looking at things inside the type? > >> > > > > >> > > > I think it could be useful for both cases. Currently, dsymutil does only first thing > >> > > > (look at type name, namespace name, etc..) and does not do the second thing > >> > > > (doing structural equivalence). Analyzing type names is currently quite expensive > >> > > > (the only search in string pool takes ~10 sec from 70 sec of overall time). > >> > > > That is expensive because of many things should be done to work with strings: > >> > > > parse DWARF, search and resolve relocations, compute a hash for strings, > >> > > > put data into a string pool, create a fully qualified name(like namespace::function::name). > >> > > > It looks like it could be optimized and finally require less time, but it still would be a noticeable > >> > > > part of the overall time. > >> > > > > >> > > > If dsymutil starts to check for the structural equivalence, then the process would be even more slowly. > >> > > > So, If instead of comparing types structure, there would be checked single hash-id - then this process > >> > > > would also be faster. > >> > > > > >> > > > Thus I think using hash-id to compare types would allow to make current implementation faster and would > >> > > > allow handling incomplete types by DWARFLinker without massive performance degradation also. > >> > > > > >> > > > >> But the context is known when types are generated. So, no need to spent the time analyzing it. > >> > > > > >> > > > >> If types could be compared without analyzing context, then Dwarf-aware linker would work faster. > >> > > > > >> > > > >> That is just an idea(not for immediate implementation): If types would be stored in some "type table" > >> > > > > >> > > > >> (instead of COMDAT section group) and could be accessed through hash-id(like type units > >> > > > > >> > > > >> - then it would be the solution requiring fewer bits to store but allowing to compare types > >> > > > > >> > > > >> by hash-id(not analysing context). > >> > > > >> In this case, size increasing would be small. And processing time could be done faster. > >> > > > >> > >> > > > >> this is just an idea and could be discussed separately from the problem of integrating of D74169. > >> > > > > >> > > > >> >> 6. -flto=thin > >> > > > > >> > > > >> >> That problem was described in this review https://reviews.llvm.org/D54747#1503720. It also exists in > >> > > > > >> > > > >> >> current DWARFLinker/dsymutil implementation. I think that problem should be discussed more: it could > >> > > > > >> > > > >> >> probably be fixed by avoiding generation of such incomplete declaration during thinlto, > >> > > > > >> > > > >> >> That would be costly to produce extra/redundant debug info in ThinLTO - actually ThinLTO could be doing > >> > > > > >> > > > >> >> more to reduce that redundancy early on (actually removing definitions from some llvm Modules if the type > >> > > > > >> > > > >> >> definition is known to exist in another Module, etc) > >> > > > >> >I don't know if it's a problem since that patch was reverted. > >> > > > > >> > > > >> > >> > > > > >> > > > >> Yes. That patch was reverted, but this patch(D74169) has the same problem. > >> > > > > >> > > > >> if D74169 would be applied and --gc-debuginfo used then structure type > >> > > > >> definition would be removed. > >> > > > > >> > > > >> DWARFLinker could handle that case - "removing definitions from some llvm Modules if the type > >> > > > >> definition is known to exist in another Module". > >> > > > >> i.e. DWARFLinker could replace the declaration with the definition. > >> > > > > >> > > > >> But that problem could be more easily resolved when debug info is generated(probably without > >> > > > >> significant increase of debug info size): > >> > > > > >> > > > >> Here we have: > >> > > > > >> > > > >> DW_TAG_compile_unit(0x0000000b) - compile unit containing concrete instance for function "f". > >> > > > >> DW_TAG_compile_unit(0x00000073) - compile unit containing abstract instance root for function "f". > >> > > > >> DW_TAG_compile_unit(0x000000c1) - compile unit containing function "f" definition. > >> > > > > >> > > > >> Code for function "f" was deleted. gc-debuginfo deletes compile unit DW_TAG_compile_unit(0x000000c1) > >> > > > >> containing "f" definition (since there is no corresponding code). But it has structure "Foo" definition > >> > > > >> DW_TAG_structure_type(0x0000011e) referenced from DW_TAG_compile_unit(0x00000073) > >> > > > >> by declaration DW_TAG_structure_type(0x000000ae). That declaration is exactly the case when definition > >> > > > >> was removed by thinlto and replaced with declaration. > >> > > > > >> > > > >> Would it cost too much if type definition would not be replaced with declaration for "abstract instance root"? > >> > > > >> The number of concrete instances is bigger than number of abstract instance roots. > >> > > > >> Probably, it would not be too costly to leave definition in abstract instance root? > >> > > > > >> > > > > >> > > > > >> > > > >> Alternatively, Would it cost too much if type definition would not be replaced with declaration when > >> > > > >> declaration references type from not used function? (lto could understand that concrete function is not used). > >> > > > > >> > > > > >> > > > >I don't follow this example - could you provide a small concrete test case I could reproduce? > >> > > > > >> > > > I would provide a test case if necessary. But it looks like this issue is finally clear, and you already commented on that. > >> > > > > >> > > > > Oh, I guess this is happening perhaps because ThinLTO can't know for sure that a standalone > >> > > > > definition of 'f' won't be needed - so it produces one in case one of the inlining opportunities > >> > > > > doesn't end up inlining. Then it turns out all calls got inlined, so the external definition wasn't needed. > >> > > > > >> > > > > Oh, you're suggesting that these 3 CUs got emitted into one object file during LTO, but that DWARFLinker > >> > > > > drops a CU without any code in it - even though... So far as I know, in LTO, LLVM directly references > >> > > > > types across units if the CUs are all emitted in the same object file. (and if they weren't in the same > >> > > > > object file - then the abstract_origin couldn't be pointing cross-CU). > >> > > > > >> > > > > I guess some basic things to say: > >> > > > > >> > > > > With ThinLTO, the concrete/standalone function definition is emitted in case some call sites don't end up > >> > > > > being inlined. So we know it'll be emitted (but might not be needed by the actual linker) > >> > > > > ANy number of inline calls might exist - but we shouldn't put the type information into those, because > >> > > > > they aren't guaranteed to emit it (if the inline function gets optimized away, there would be nothing to > >> > > > > enforce the type being emitted) - and even if we forced the type information to be emitted into one > >> > > > > object file that has an inline copy of the function - there's no guarantee that object file will get linked in either. > >> > > > > >> > > > > So, no, I don't think there's much we can do to keep the size of object files down, while guaranteeing > >> > > > > the type information will be emitted with the usual linker semantics. > >> > > > > >> > > > Then dsymutil/DWARFLinker could be changed to handle that(though it would probably be not very efficient). > >> > > > If thinlto would understand that function is not used finally(and then must not contain referenced type definition), > >> > > > then this situation could be handled more effectively. > >> > > > > >> > > > Thank you, Alexey. > >> > > > > >> > > >>> > >> > > >>> > >> > > >>> > >> > > >>> > >> > > >>> _______________________________________________ > >> > > >>> LLVM Developers mailing list > >> > > >>> llvm-dev at lists.llvm.org > >> > > >>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > >> > > _______________________________________________ > >> > > LLVM Developers mailing list > >> > > llvm-dev at lists.llvm.org > >> > > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > >_______________________________________________ > >LLVM Developers mailing list > >llvm-dev at lists.llvm.org > >https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
bd1976 llvm via llvm-dev
2020-Jun-24 15:15 UTC
[llvm-dev] [Debuginfo][DWARF][LLD] Remove obsolete debug info in lld.
Thanks for copying me in Paul! Sorry, for the late reply. I have had a personal interest in this subject for a long time and I have had discussions on linking DWARF with many of you in person at LLVM events. I don't have much to add to what's upthread and James Henderson has already answered the questions I was copied in for. However, I did want to make a general point about ELF that I thought might be helpful having read through the above: It may be that changes to the ELF spec might be warranted in order to improve DWARF linking (on ELF). Everyone may already be aware of this but FYI: the ownership of ELF has been a problem for a while. Currently, the ELF spec is composed of the spec here: http://www.sco.com/developers/gabi/ plus the decisions made on the list: https://groups.google.com/forum/#!forum/generic-abi. Obviously, this is less than ideal. However, this is hopefully changing in the near future see: https://groups.google.com/forum/#!topic/generic-abi/9OO5vhxb00Y. This should mean that modifications to ELF are more viable in the future. On Tue, Jun 23, 2020 at 10:42 PM David Blaikie via llvm-dev < llvm-dev at lists.llvm.org> wrote:> On Tue, Jun 23, 2020 at 2:19 PM Alexey Lapshin > <alapshin at accesssoftek.com> wrote: > > > > >On 2020-06-22, Alexey Lapshin via llvm-dev wrote: > > >>>> >> >Alexey> Probably we could try to make DWARF easy to parsing, > trimming, rewriting so that full DWARF > > >>>> >> >Alexey> parsing solution would not take too much time? > > >>>> >> >Alexey> > > >>>> >> >Alexey> f.e. -debug-types-section solution uses COMDAT sections > to split and deduplicate types. > > >>>> >> >Alexey> That solution works quite fast. It has already > mentioned drawback with a big size > > >>>> >> >Alexey> overhead(because of section headers/type unit headers > sizes). But, the fact that type units > > >>>> >> >Alexey> could be identified just by hash-id(without parsing > type names and types hierarchies) > > >>>> >> >Alexey> allows the linker to reject duplications quickly. > Another thing is that the linker drops > > >>>> >> >Alexey> duplicated COMDAT sections without any additional > check. After duplications are deleted, > > >>>> >> >Alexey> the debug info is still consistent. > > >>>> >> >Alexey> There could be done DWARF aware solution working using > the same two principles: > > >>>> >> >Alexey> 1. compare types by hash-id. > > >>>> >> >Alexey> 2. drop duplications without analyzing contents. > > >>>> >> >Alexey> > > >>>> >> >Alexey> If all types are put into a separate type table and > have hash-id, then it would be much easier to > > >>>> >> >Alexey> deduplicate them. The idea demonstrated here - > https://reviews.llvm.org/P8164. (It still has a > > >>>> >> >Alexey> questions: whether base types should be put into type > table, whether references into type table > > >>>> >> >Alexey> should be done by DW_AT_signature or just by offset, > etc.. ) While handling that separate type table > > >>>> >> >Alexey> the DWARF aware linker would check the only hash_id and > put only one type description > > >>>> >> >Alexey> with the same id in the final type table. It also would > allow us to solve that -flto=thin problem - > > >>>> >> >Alexey> > http://lists.llvm.org/pipermail/llvm-dev/2020-May/141938.html (there is > dsymutil example there). > > >>>> >> >Alexey> i.e., the case when type definition would be removed > will not occur. > > >>>> >> > > >>>> >> David>I think there is scope for lower-overhead type > deduplication, > > >>>> >> David>especially now with type units being merged into the > debug_info > > >>>> >> David>section. Perhaps we could drop dwo_ids and use section > references to > > >>>> >> David>refer to types & rely on the linker to keep those > referenced sections > > >>>> >> David>alive - though section references are longer than > CU-relative > > >>>> >> David>references. (but we need the extra length - because if the > linker > > >>>> >> David>deduplicates a type definition - one CU may be referencing > a type very > > >>>> >> David>far away, so the shorter reference might be inadequate) I > don't think > > >>>> >> David>the indirection through the type hash is /super/ > significant to the > > >>>> >> David>cost - I think it's more in the duplication of many DIEs > especially > > >>>> >> David>for function definitions (since the type unit sig8 system > only > > >>>> >> David>provides a way to reference the type - not its member > functions, their > > >>>> >> David>parameters, etc - so all those DIEs get duplicated in any > CU that > > >>>> >> David>needs to provide a definition of a member function). We > could > > >>>> >> David>prototype cross-unit DIE references to lower the cost of > that > > >>>> >> David>duplication, though rumor has it that constructor based > type homing > > >>>> >> David>might provide enough value to obviate the need for type > units (or at > > >>>> >> David>least make the overhead not worthwhile - so revisiting the > overhead to > > >>>> >> David>reduce it might make it worthwhile again... ). > > >>>> >> > > >>>> >> David>Probably wouldn't be super hard to use LLVM's existing > cross-unit DIE > > >>>> >> David>Referencing machinery (implemented for LTO) to refer > directly to DIEs > > >>>> >> David>in a type unit without using the signature system... - > hmm, that'd > > >>>> >> David>only work if your type unit DIEs were identical? /maybe/ ? > Not sure > > >>>> >> David>how that'd work if you wanted to refer into a type unit, > but the type > > >>>> >> David>unit got deduplicated. Might be able to rely on the linker > to preserve > > >>>> >> David>every unique copy of the type unit that's referenced if we > phrase > > >>>> >> David>things carefully - so if your compiler does produce > exactly identical > > >>>> >> David>type units they get deduplicated and sec_refs refer to the > uniquely > > >>>> >> David>preserved copy - but otherwise it preserves as many > distinct copies as > > >>>> >> David>needed. (I don't know enough about how that works to be > sure - but I > > >>>> >> David>know that these linkonce/inline function deduplication > does seem to > > >>>> >> David>cause the DWARF to refer to the singular function if that > function is > > >>>> >> David>identical, and if it isn't, then you get 0 - so there's > /something/ in > > >>>> >> David>the linker that can adjust for deduplicating identical > duplicates... ) > > >>>> >> > > >>>> >> Probably I was a bit unclear: the above idea is not for types > > >>>> >> (placed in COMDAT sections) deduplicated by the linker. > > >>>> > > >>>> >Yeah, I was just wondering whether it could be useful for that too. > > >>>> > > >>>> >> This idea goes in another direction than fragmenting dwarf > > >>>> >> using elf sections&tricks. It seems to me that the cost of > fragmenting is too high. > > >>>> > > >>>> >I tend to agree - but I'm sort of leaning towards trying to use > object > > >>>> >features as much as possible, then implementing just enough custom > > >>>> >handling in the linker to recoup overhead, etc. (eg: add some kind > of > > >>>> >small header/brief description that makes it easy for the linker to > > >>>> >slice-and-dice - but hopefully a domain-specific such header can > be a > > >>>> >bit more compact than the fully general ELF form) > > >>>> > > >>>> I think this indeed should be implemented and evaluated. > > >>>> So that various approaches could be compared. > > >>>> > > >>>> >> It is not only the sizes of structures describing fragments but > also the complexity > > >>>> >> of tools that should be taught to work with fragmented DWARF. > > >>>> >> (f.e. llvm-dwarfdump applied to object file should be able to > read fragmented DWARF, > > >>>> >> but applied to linked executable it should work with > non-fragmented DWARF). > > >>>> >> That idea is for the tool which works the same way as dsymutil > ODR. > > >>>> >> > > >>>> >> I will shortly describe the idea of making DWARF be easier > processed by dsymutil/DWARFLinker: > > >>>> >> > > >>>> >> The idea is to have only one "type table" per object > file(special section .debug_types_table). > > >>>> >> This "type table" would contain all types. > > >>>> >> There could be a special type of reference - type_offset - that > offset points into the type table. > > >>>> >> Basic types could always be placed into the start of "type > table" thus, offsets to basic types > > >>>> >> most often would be 1 byte. There also would be a special kind > of reference - reference inside the type. > > >>>> >> Type units sig8 system - would not be used to reference types. > > >>>> >> > > >>>> >> Types deduplication is assumed to be done, not by linker > mechanism for COMDAT, > > >>>> >> but by a tool like dsymutil. This tool would create resulting > .debug_types_table by putting there > > >>>> >> types from source .debug_types_table-s. Only one copy of the > type would be placed into the > > >>>> >> resulting table. All references pointing to the deleted copy > would be corrected to point > > >>>> >> to the single copy inside "type table". (that is how dsymutil > works currently) > > >>>> > > >>>> >^ that's the step that's probably a bit expensive for a general-use > > >>>> >tool - it implies parsing all the DWARF to find those references > and > > >>>> >rewrite them, I think. For a high-performance solution that could > be > > >>>> >run by the linker I think it'd be necessary to have a solution that > > >>>> >doesn't involve parsing all the DIEs. > > >>>> > > >>>> According to the current dsymutil processing, > > >>>> exactly this process is not the most time-consuming. > > >>>> That could be done relatively fast. > > >> > > >>>Fair enough - though I'd still imagine any solution that involves > > >>>parsing all the DIEs still wouldn't be fast enough (maybe an order of > > >>>magnitude faster than the current solution even - but that's stuill, > > >>>what, 6 or 7x slower than linking without the feature?) for most users > > >>>to consider it a good trade-off. > > >> > > >>It seems to me that even the current 6x-7x slowdown could be useful. > > >>Users who already use dsymutil or llvm-dwp(assuming DWARFLinker > > >>would be taught to work with a split dwarf) tools spend this time and, > > >>in some scenarios, waste disk space by inter-mediate files. > > >>Thus if they would use this LLD feature in its current state > > >>- they would still receive benefits. > > >> > > >>Speaking of performance results - LLD is a multi-thread linker; > > >>it handles sections in parallel. DWARFLinker generates DWARF using > > >>AsmPrinter which is a stream - so it could make resulting DWARF only > > >>continuously. It is not surprising that the parallel solution works > faster. > > >>Making DWARFLinker truly multi-threaded would probably allow us > > >>to make slowdown to be at 2x-4x range. > > > > > >If it is 6x-7x slowdown (which may be optimized to 2x-4x), I wonder > > >whether it is a good trade-off keeping it as an in-linker pass, or > > >rather we should just use another utility compressing the output > separately. > > > > > >If the slowdown is such a pain, I might not consider --gc-debuginfo a > > >readily usable feature like --gdb-index or future --debug-names (DWARF > > >v5 accelator table - I have a plan to add it but I am always distracted > > >by other priorities at hand). Considering that this breaks GNU linkers, > > >I will add the following lines to the build system > > > > > > if LINKER_IS_LLD && ENABLE_GC_DEBUGINFO > > > add -Wl,--gc-debuginfo > > > > > >I don't think this is more complex than: > > > > > > if ENABLE_GC_DEBUGINFO > > > set linker to a wrapper which optimizes the output like dwz > > > > > >We probably should add another -f option for specifying the linker path, > > >like -fld-path> https://lists.llvm.org/pipermail/cfe-dev/2020-June/065710.html > > > > gc-debuginfo could be done not from linker but as a standalone > > tool(like dsymutil,llvm-dwp), as you said. The reasons why it > > was suggested to do from the linker: > > > > 1. Linker already has liveness information built and object files loaded. > > Thus, it would be the fastest implementation if called from the > linker. > > Otherwise, there should be created and written address map while > > linking, there should be generated inter-mediate debug-info files. > > And then, the separate tool would read that map and load object files > > or inter-mediate debug-info files again. So processing time > > would become even longer. > > I think the suggestion would be to link as normal, then process to > optimize (like dwz - I believe it does something like this too). It > wouldn't need a map from the linker - it could use the existing > tombstone values in the linked DWARF to determine what to drop. Yes, > the processing time would be longer, for sure. (I think Fangrui's > suggestion there is "if you're willing to take a (let's say optimized) > 2x or more increase to link time, maybe (let's say doing the > intermediate step adds some fairly significant chunk of overhead) 3x > wouldn't make too much of a difference?) > > > 2. Linker already processes debug info: error reporting, > > It's important that it's only consulted in the error path - if the > link is failing anyway, taking a little longer to fail isn't likely to > significantly hurt the user experience (compared to the time it takes > a human to read the message, process it/think about what it means and > come up with a theory about how to address it). Compared to getting in > the way of the automated path to a working executable. > > > --gdb-index, > > upcoming --debug-names. > > Importantly, these can be produced without parsing a lot of DWARF if > the input contains gnu_pubnames, or debug_names (yeah, currently > gdb_index still is quite costly (but I think more like 10s of percent > in link time, not multiple 100s of percent) in memory and link time > even when it's only parsing gnu_pubnames. > > > From the design point of view, it would be > > good to have a separate module - DWARFLinker - which implements > > all that functionality. So that there would not be additional > separate > > specific linker implementation of them. Instead, already existed > > implementation would be called from the linker. i.e. Depending on the > > tasks, the linker would call either DWARFLinker.generate-gdb-index(), > > DWARFLinker.generate-debug-names(), DWARFLinker.gc-debuginfo(). > > > > The idea behind gc-debuginfo was not to slowdown the linking process for > everybody. > > But to allow generation optimized debug-info for those who need it. > > That is the same idea as LTO. LTO slowdowns usual compilation > significantly, > > but it creates a highly optimized code. > > Yep - I think the main difference there is going to be the size of the > user base compared to the complexity (certainly LTO adds complexity to > the linker - though without much alternative (well, alternative would > be build systems being aware of this - sort of like Fangrui's > suggestion, LTO could be a separate tool that merges LLVM bitcode > files, then creates real object files that go to the actual native > linker) to gain the desired performance). > > Fangrui: What's your assessment of the complexity of adding this > functionality to lld? Are you concerned it'll be an ongoing > maintenance burden on other work in lld? If not, I'd be inclined > to/lean towards accepting this & having some room for Alexey to > improve the performance for his own users needs (& hopefully that'll > improve DWARFLinker functionality/performance as well), see if anyone > else wants this link time tradeoff. > > - Dave > > > > > Thank you, Alexey. > > > > >>> Anyway, I think the dsymutil approach is still valuable, and it > > >>> would be useful to optimize it. > > >>> Do you think it would be useful to make dsymutil/DWARFLinker truly > multi-thread? > > >>> (To make dsymutil/DWARFLinker able to process each object file in a > separate thread) > > > > > >>Perhaps - that I'd probably leave up to the folks who are more > > >>invested in dsymutil (Adrian Prantl et al). Maybe one day we'll get it > > >>integrated into llvm-dwp and then I'll be interested in getting as > > >>much performance out of it as lld - so multithreading and things would > > >>be on the books. > > > > > >I think improving dsymutil is a valuable thing. > > >Though there are several directions which might be considered > > >to make it more robust: > > > > > >1. support of latest DWARF - DWARF5/DWARF64... > > >2. implement multi-threaded execution. > > >3. support of split DWARF. > > >4. implement dsymutil for non-darwin platform. > > > > > >All of this is a massive piece of work. > > >Our original investment was to solve two problems: > > > > > >1. Overlapped address ranges, which is currently close to being solved. > Thank you for helping with that! > > > > > >2. Size of debug info. That still becomes an issue, but we are unsure > whether we are ready to > > > invest in solving all the above 1-4 problems and how much community > interested in it. > > > > > >Thank you, Alexey. > > > > > >>> >One way to do that would be to have a CU-local type indirection > table. > > >>> >DIEs reference local type numbers (like local address/string > numbers - > > >>> >addrx/strx/rnglistx) and that table contains either sig8 (no linker > > >>> >fixups required) or the local type offsets you describe - the linker > > >>> >would then only need to read this type number indirection table and > > >>> >rewrite them to the final type numbers. > > >>> > > >>> Yes, that could be additionally done if this process would be > time-consuming. > > >>> > > >>> David, thank you for all your comments and explanations. They are > extremely helpful. > > > > > >>Sure thing - really appreciate your patience with all this - it's... a > > >>lot of moving parts. > > > > > >>- Dave > > > > > >> > > >> Thank you, Alexey. > > >> > > >> > sig8 hash-id would be used to compare types and to deduplicate them. > > >> > It would speed up the current dsymutil context analysis. > > >> > Types having the same hash-id could be deduplicated. > > >> > This would allow deduplicating a more number of types than current > dsymutil. > > >> > Incomplete type definitions having a similar set of members are not > deduplicated by dsymutil currently. > > >> > In this case they would have the same hash-id. > > >> > > > >> > This "type table" would take less space than current "type units" > and current ODR solution. > > >> > > > >> > Above is just an idea on how to help DWARF-aware linker(based on > idea removing obsolete debug info) > > >> > to work faster(if that is interesting). > > >> > > > >> > Alexey. > > >> > > > >> > > From: llvm-dev <llvm-dev-bounces at lists.llvm.org> On Behalf Of > James Henderson via llvm-dev > > >> > > Sent: Wednesday, June 3, 2020 3:48 AM > > >> > > To: David Blaikie <dblaikie at gmail.com> > > >> > > Cc: llvm-dev at lists.llvm.org > > >> > > Subject: Re: [llvm-dev] [Debuginfo][DWARF][LLD] Remove obsolete > debug info in lld. > > >> > > > > >> > > > > >> > > > > >> > > It makes me sad that the linker (via a library or otherwise) has > to be "DWARF-aware" to be able to effectively handle --gc-sections, > COMDATs, --icf etc for debug info, without leaving large blocks of data > kicking around. > > >> > > > > >> > > > > >> > > > > >> > > The patching to -1 (or equivalent) is probably a good lightweight > solution (though I'd love it if it could be done based on section type in > the future rather than section name, but that's probably outside the realm > of DWARF), as it requires only minimal understanding in the linker, but > anything beyond that seems to be complicated logic that is mostly due to > the structure of DWARF. Patching to -1 does feel a bit like a sticking > plaster/band aid to patch over the issue rather than properly solving it > too - there will still be debug data (potentially significant amounts in > COMDAT-heavy objects) that the linker has to write and the debugger has to > somehow know how to skip (even if it knows that -1 is special-case due to > the standard being updated, it needs to get as far as the -1), which is all > wasted effort. > > >> > > > > >> > > > > >> > > > > >> > > We've already seen from Alexey's prototyping, and from our own > experiences with the Sony proprietary linker (which tried to rewrite > .debug_line only) that deconstructing the DWARF so that it can be more > optimally reassembled at link time is slow going, and will probably > inevitably be however much effort is put into optimising it. For a start, > given the current standards, it's impossible to know how to deconstruct it > without having to parse vast amounts of DWARF, which is typically going to > mean a lot more parsing work than the linker would normally have to deal > with. Additionally, much of this parsing work is wasted effort, since it > seems unlikely in many links that large amounts of the DWARF will be > redundant. Having an option to opt-in doesn't help much there, since it > just means the logic exists without most people using it, due to it not > being good enough, or potentially they don't even know it exists. > > >> > > > > >> > > > > >> > > > > >> > > I don't have particularly concrete suggestions as to how to solve > the structural problems with DWARF at this point. The only thing that seems > obvious to me is a more "blessed" approach to fragmentation of sections, > similar to what I tried with my prototype mentioned earlier in the thread, > although we'd need to figure out the previously stated performance issues. > Other ideas might tie into this, like somehow sharing the various table > headers a bit like CIEs in .eh_frame that could be merged by the linker - > each object could have separate table header sections, which are referenced > by the individual .debug_* blocks, which in turn are one per function/data > piece and easily discardable/merged by the linker. > > >> > > > > >> > > > > >> > > > > >> > > Just some thoughts. > > >> > > > > >> > > > > >> > > > > >> > > James > > >> > > > > >> > > > > >> > > > > >> > > On Tue, 2 Jun 2020 at 19:24, David Blaikie via llvm-dev < > llvm-dev at lists.llvm.org> wrote: > > >> > > > > >> > > On Tue, May 19, 2020 at 7:17 AM Alexey Lapshin > > >> > > <alapshin at accesssoftek.com> wrote: > > >> > > > > > >> > > > Hi David, please find my comments inside: > > >> > > > > > >> > > > > > >> > > > >>>Broad question: Do you have any specific > motivation/users/etc in implementing this (if you can speak about it)? > > >> > > > > > >> > > > >>> - it might help motivate the work, understand what > tradeoffs might be suitable for you/your users, etc. > > >> > > > > > >> > > > >>There are two general requirements: > > >> > > > >> 1) Remove (or clean) invalid debug info. > > >> > > > > > >> > > > > > > >> > > > >Perhaps a simpler direct solution for your immediate needs > might be a much narrower, > > >> > > > >and more efficient linker-DWARF-awareness feature: > > >> > > > > > > >> > > > > With DWARFv5, rnglists present an opportunity for a DWARF > linker to rewrite the ranges > > >> > > > > without parsing the rest of the DWARF. /technically/ this > isn't guaranteed - rnglist entries > > >> > > > > can be referenced either directly, or by index. If all > rnglists are referenced by index, then > > >> > > > > a linker could parse only the debug_rnglists section and > rewrite ranges to remove any > > >> > > > > address ranges that refer to optimized-out code. > > >> > > > > > > >> > > > > This would only be correct for rnglists that had no direct > references to them (that only were > > >> > > > > referenced via the indexes) - but we could either implement > it with that assumption, or could > > >> > > > > add an LLVM extension attribute on the CU that would say "I > promise I only referenced rnglists > > >> > > > > via rnglistx forms/indexes). If this DWARF-aware linking > would have to read the CU DIE (not > > >> > > > > all the other DIEs) it /could/ also then rewrite high/low_pc > if the CU wasn't using ranges... > > >> > > > > but that wouldn't come up in the function-removal case, > because then you'd have ranges anyway, > > >> > > > > so no need for that. > > >> > > > > > > >> > > > > Such a DWARF-aware rnglist linking could also simplify > rnglists, in cases where functions > > >> > > > > ended up being laid out next to each other, the linker could > coalesce their ranges together. > > >> > > > > > > >> > > > > I imagine this could be implemented with very little overhead > to linking, especially compared > > >> > > > > to the overhead of full DWARF-aware linking. > > >> > > > > > > >> > > > >Though none of this fixes Split DWARF, where the linker > doesn't get a chance to see the > > >> > > > > addresses being used - but if you only want/need the CU-level > ranges to be correct, this > > >> > > > > might be a viable fix, and quite efficient. > > >> > > > > > >> > > > Yes, we think about that alternative. This would resolve our > problem of invalid debug info > > >> > > > and would work much faster. Thus, if we would not have good > results for D74169 then we > > >> > > > will implement it. Do you think it could be useful to have this > solution in upstream? > > >> > > > > >> > > A pure rnglist rewriting - I think it'd be OK to have in upstream > - > > >> > > again, cost/benefit/etc would have to be weighed. I'm not sure it > > >> > > would save enough space to be particularly valuable beyond the > > >> > > correctness issue - and it doesn't completely solve the > correctness > > >> > > issue for zero-address usage or low-address usage (because you > could > > >> > > still have overlapping subprograms inside a CU - so if you were > > >> > > symbolizing you could use the correct rnglist to filter, but then > go > > >> > > look inside the CU only to find two subprograms that had that > address > > >> > > & not know which one was the correct one an which one was the > > >> > > discarded one). > > >> > > > > >> > > rnglist rewriting might be easy enough to prototype - but depends > what > > >> > > you want to spend your time on, I know this whole issue has been a > > >> > > huge investment of your time already - but maybe this recent > > >> > > revitalization of the conversation around having an explicit > value in > > >> > > the linker might be sufficient to address everyone's needs... > *fingers > > >> > > crossed*) > > >> > > > > >> > > > > >> > > > >> 2) Optimize the DWARF size. > > >> > > > > > >> > > > > > >> > > > > Do your users care much about this? I imagine if they had > significant DWARF size issues, > > >> > > > > they'd have significant link time issues and the kind of cost > to link time this feature has would > > >> > > > > be prohibitive - but perhaps they're sharing linked binaries > much more often than they're > > >> > > > > actually performing linking. > > >> > > > > > >> > > > Yes, they do. They also have significant link-time issues. > > >> > > > So current performance results of D74169 are not very > acceptable. > > >> > > > We hope to improve it. > > >> > > > > > >> > > > > > >> > > > > > >> > > > >>The specifics which our users have: > > >> > > > >> - embedded platform which uses 0 as start of .text section. > > >> > > > >> - custom toolset which does not support all features > yet(f.e. split dwarf). > > >> > > > >> - tolerant of the link-time increase. > > >> > > > >> - need a useful way to share debug builds. > > >> > > > > > >> > > > > > >> > > > > Sharing two files (executable and dwp) is significantly less > useful than sharing one file? > > >> > > > > > >> > > > Probably not significantly, but yes, it looks less useful > comparing to D74169. > > >> > > > Having only two files (executable and .dwp) looks significantly > better than having executable and multiple .dwo files. > > >> > > > Having only one file(executable) with minimal size looks better > than the two files with a bigger size. > > >> > > > > > >> > > > clang compiled with -gsplitdwarf takes 0.9G for executable and > 0.9G for .dwp. > > >> > > > clang compiled with -gc-debuginfo takes only 0.76G for single > executable. > > >> > > > > > >> > > > > > >> > > > > > >> > > > >>For the first point: we have a problem "Overlapping address > ranges starting from 0"(D59553). > > >> > > > > > >> > > > >>We use custom solution, but the general solution like D74169 > would be better here. > > >> > > > > > >> > > > > > >> > > > > If CU ranges are the only ones that need fixing, then I think > the above solution might be as > > >> > > > > good/better - if more than CU ranges need fixing, then I > think we might want to start talking about > > >> > > > > how to fix DWARF itself (split and non-split) to signal > certain addresses point to dead code with a > > >> > > > > specific blessed value that linkers would need to implement - > because with Split DWARF there's > > >> > > > > no way to solve the non-CU addresses at the linker. > > >> > > > > > >> > > > I think the worthful solution for that signal value would be > LowPC > HighPC. > > >> > > > That does not require additional bits in DWARF. > > >> > > > It would be natural to skip such address ranges since they > explicitly marked as invalid. > > >> > > > It could be implemented in a linker very easily. Probably, it > would make sense to describe that > > >> > > > usage in DWARF standard. > > >> > > > > > >> > > > As to the addresses which are not seen by the linker(since they > are in .dwo files) - yes, > > >> > > > they need to have another solution. Could you show an example > of such a case, please? > > >> > > > > > >> > > > > > >> > > > > > >> > > > >>>2. Support of type units. > > >> > > > > > >> > > > >>> > > >> > > > > > >> > > > >>>> That could be implemented further. > > >> > > > > > >> > > > >>>Enabling type units increases object size to make it easier > to deduplicate at link time by a DWARF-unaware > > >> > > > > > >> > > > >>>linker. With a DWARF aware linker it'd be generally > desirable not to have to add that object size overhead to > > >> > > > > > >> > > > >>>get the linking improvements. > > >> > > > > > >> > > > >> > > >> > > > > > >> > > > >>But, DWARFLinker should adequately work with type units since > they are already implemented. > > >> > > > > > >> > > > > > >> > > > > Maybe - it'd be nice & all, but I don't think it's an > outright necessity - if someone knows they're using > > >> > > > > a DWARF-aware linker, they'd probably not use type units in > their object files. It's possible someone > > >> > > > > doesn't know for sure & maybe they have pre-canned debug > object files from someone else, etc. > > >> > > > > > >> > > > I see. > > >> > > > > > >> > > > >>Another thing is that the idea behind type units has the > potential to help Dwarf-aware linker to work faster. > > >> > > > > > >> > > > >>Currently, DWARFLinker analyzes context to understand whether > types are the same or not. > > >> > > > > > >> > > > > > >> > > > >When you say "analyzes context" what do you mean? Usually I'd > take that to mean > > >> > > > > "looks at things outside the type itself - like what > namespace it's in, etc" - which, yes, > > >> > > > > it should do that, but it doesn't seem very expensive to do. > But I guess you actually > > >> > > > > mean something about doing structural equivalence in some > way, looking at things inside the type? > > >> > > > > > >> > > > I think it could be useful for both cases. Currently, dsymutil > does only first thing > > >> > > > (look at type name, namespace name, etc..) and does not do the > second thing > > >> > > > (doing structural equivalence). Analyzing type names is > currently quite expensive > > >> > > > (the only search in string pool takes ~10 sec from 70 sec of > overall time). > > >> > > > That is expensive because of many things should be done to work > with strings: > > >> > > > parse DWARF, search and resolve relocations, compute a hash for > strings, > > >> > > > put data into a string pool, create a fully qualified name(like > namespace::function::name). > > >> > > > It looks like it could be optimized and finally require less > time, but it still would be a noticeable > > >> > > > part of the overall time. > > >> > > > > > >> > > > If dsymutil starts to check for the structural equivalence, > then the process would be even more slowly. > > >> > > > So, If instead of comparing types structure, there would be > checked single hash-id - then this process > > >> > > > would also be faster. > > >> > > > > > >> > > > Thus I think using hash-id to compare types would allow to make > current implementation faster and would > > >> > > > allow handling incomplete types by DWARFLinker without massive > performance degradation also. > > >> > > > > > >> > > > >> But the context is known when types are generated. So, no > need to spent the time analyzing it. > > >> > > > > > >> > > > >> If types could be compared without analyzing context, then > Dwarf-aware linker would work faster. > > >> > > > > > >> > > > >> That is just an idea(not for immediate implementation): If > types would be stored in some "type table" > > >> > > > > > >> > > > >> (instead of COMDAT section group) and could be accessed > through hash-id(like type units > > >> > > > > > >> > > > >> - then it would be the solution requiring fewer bits to > store but allowing to compare types > > >> > > > > > >> > > > >> by hash-id(not analysing context). > > >> > > > >> In this case, size increasing would be small. And processing > time could be done faster. > > >> > > > >> > > >> > > > >> this is just an idea and could be discussed separately from > the problem of integrating of D74169. > > >> > > > > > >> > > > >> >> 6. -flto=thin > > >> > > > > > >> > > > >> >> That problem was described in this review > https://reviews.llvm.org/D54747#1503720. It also exists in > > >> > > > > > >> > > > >> >> current DWARFLinker/dsymutil implementation. I think that > problem should be discussed more: it could > > >> > > > > > >> > > > >> >> probably be fixed by avoiding generation of such > incomplete declaration during thinlto, > > >> > > > > > >> > > > >> >> That would be costly to produce extra/redundant debug > info in ThinLTO - actually ThinLTO could be doing > > >> > > > > > >> > > > >> >> more to reduce that redundancy early on (actually > removing definitions from some llvm Modules if the type > > >> > > > > > >> > > > >> >> definition is known to exist in another Module, etc) > > >> > > > >> >I don't know if it's a problem since that patch was > reverted. > > >> > > > > > >> > > > >> > > >> > > > > > >> > > > >> Yes. That patch was reverted, but this patch(D74169) has the > same problem. > > >> > > > > > >> > > > >> if D74169 would be applied and --gc-debuginfo used then > structure type > > >> > > > >> definition would be removed. > > >> > > > > > >> > > > >> DWARFLinker could handle that case - "removing definitions > from some llvm Modules if the type > > >> > > > >> definition is known to exist in another Module". > > >> > > > >> i.e. DWARFLinker could replace the declaration with the > definition. > > >> > > > > > >> > > > >> But that problem could be more easily resolved when debug > info is generated(probably without > > >> > > > >> significant increase of debug info size): > > >> > > > > > >> > > > >> Here we have: > > >> > > > > > >> > > > >> DW_TAG_compile_unit(0x0000000b) - compile unit containing > concrete instance for function "f". > > >> > > > >> DW_TAG_compile_unit(0x00000073) - compile unit containing > abstract instance root for function "f". > > >> > > > >> DW_TAG_compile_unit(0x000000c1) - compile unit containing > function "f" definition. > > >> > > > > > >> > > > >> Code for function "f" was deleted. gc-debuginfo deletes > compile unit DW_TAG_compile_unit(0x000000c1) > > >> > > > >> containing "f" definition (since there is no corresponding > code). But it has structure "Foo" definition > > >> > > > >> DW_TAG_structure_type(0x0000011e) referenced from > DW_TAG_compile_unit(0x00000073) > > >> > > > >> by declaration DW_TAG_structure_type(0x000000ae). That > declaration is exactly the case when definition > > >> > > > >> was removed by thinlto and replaced with declaration. > > >> > > > > > >> > > > >> Would it cost too much if type definition would not be > replaced with declaration for "abstract instance root"? > > >> > > > >> The number of concrete instances is bigger than number of > abstract instance roots. > > >> > > > >> Probably, it would not be too costly to leave definition in > abstract instance root? > > >> > > > > > >> > > > > > >> > > > > > >> > > > >> Alternatively, Would it cost too much if type definition > would not be replaced with declaration when > > >> > > > >> declaration references type from not used function? (lto > could understand that concrete function is not used). > > >> > > > > > >> > > > > > >> > > > >I don't follow this example - could you provide a small > concrete test case I could reproduce? > > >> > > > > > >> > > > I would provide a test case if necessary. But it looks like > this issue is finally clear, and you already commented on that. > > >> > > > > > >> > > > > Oh, I guess this is happening perhaps because ThinLTO can't > know for sure that a standalone > > >> > > > > definition of 'f' won't be needed - so it produces one in > case one of the inlining opportunities > > >> > > > > doesn't end up inlining. Then it turns out all calls got > inlined, so the external definition wasn't needed. > > >> > > > > > >> > > > > Oh, you're suggesting that these 3 CUs got emitted into one > object file during LTO, but that DWARFLinker > > >> > > > > drops a CU without any code in it - even though... So far as > I know, in LTO, LLVM directly references > > >> > > > > types across units if the CUs are all emitted in the same > object file. (and if they weren't in the same > > >> > > > > object file - then the abstract_origin couldn't be pointing > cross-CU). > > >> > > > > > >> > > > > I guess some basic things to say: > > >> > > > > > >> > > > > With ThinLTO, the concrete/standalone function definition is > emitted in case some call sites don't end up > > >> > > > > being inlined. So we know it'll be emitted (but might not be > needed by the actual linker) > > >> > > > > ANy number of inline calls might exist - but we shouldn't put > the type information into those, because > > >> > > > > they aren't guaranteed to emit it (if the inline function > gets optimized away, there would be nothing to > > >> > > > > enforce the type being emitted) - and even if we forced the > type information to be emitted into one > > >> > > > > object file that has an inline copy of the function - there's > no guarantee that object file will get linked in either. > > >> > > > > > >> > > > > So, no, I don't think there's much we can do to keep the size > of object files down, while guaranteeing > > >> > > > > the type information will be emitted with the usual linker > semantics. > > >> > > > > > >> > > > Then dsymutil/DWARFLinker could be changed to handle > that(though it would probably be not very efficient). > > >> > > > If thinlto would understand that function is not used > finally(and then must not contain referenced type definition), > > >> > > > then this situation could be handled more effectively. > > >> > > > > > >> > > > Thank you, Alexey. > > >> > > > > > >> > > >>> > > >> > > >>> > > >> > > >>> > > >> > > >>> > > >> > > >>> _______________________________________________ > > >> > > >>> LLVM Developers mailing list > > >> > > >>> llvm-dev at lists.llvm.org > > >> > > >>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > > >> > > _______________________________________________ > > >> > > LLVM Developers mailing list > > >> > > llvm-dev at lists.llvm.org > > >> > > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > > >_______________________________________________ > > >LLVM Developers mailing list > > >llvm-dev at lists.llvm.org > > >https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200624/5dd81b60/attachment-0001.html>
Apparently Analagous Threads
- [Debuginfo][DWARF][LLD] Remove obsolete debug info in lld.
- [Debuginfo][DWARF][LLD] Remove obsolete debug info in lld.
- [Debuginfo][DWARF][LLD] Remove obsolete debug info in lld.
- [Debuginfo][DWARF][LLD] Remove obsolete debug info in lld.
- [Debuginfo][DWARF][LLD] Remove obsolete debug info in lld.