To those people I say: Look, it's a small change to software structure that lead to non-trivial improvement in size. How many opportunities does your code have for this? Such optimizations have a compounding effect, and if you habitually ignore them we end up with resource gluttony and performance issues. By the time you end up with Electron apps it almost seems hopeless and people say "well 2gig is OK, most systems have 16 or 32gig these days.
Once you focus on optimisation for a bit and learn what works, it can become as fun as developing new features and your code will be better for it. Give it a try!
Comparative benchmarks when generating 1,000,000 SVGs from TeX expressions, 1 run each, no warm-up:
* NumberFormat: 778060 milliseconds (~13 minutes)
* RyuDouble: 421160 milliseconds (~7 minutes)
Eventually I replaced JMathTeX with my NTS fork[4] and replaced the JFreeSVG library with a custom class to create SVG document strings[5].
Going from non-real-time TeX to real-time TeX rendering was worth it.
[0]: https://github.com/DaveJarvis/keenwrite
[1]: https://jmathtex.sourceforge.net/
[2]: https://github.com/jfree/jfreesvg/
[3]: https://github.com/async-profiler/async-profiler
[4]: https://github.com/DaveJarvis/KeenType
[5]: https://github.com/DaveJarvis/KeenType/blob/main/svg/src/mai...
[6]: https://github.com/jfree/jfreesvg/pull/30 (bonus link)
P.S. Eventually, I replaced the Ryu Algorithm with an even faster (and simpler) double-to-string conversion:
https://github.com/DaveJarvis/KeenType/blob/main/tex/src/mai...
That is one of those jumps that completely changes the nature of an app. IMHO on today's computers almost everything should feel like real time. Highly interactive at the very least.
On the other hand, how easy it was to find the size of every function is amazing to me... kudos to the rust community.
FWIW, ELF symbol tables record the size of all symbols, including function ones, so something like `objdump -tj .text EXECUTABLE` will print the size of every (presumably) function in the .text section of EXECUTABLE in objdump's somewhat annoying native format. More generically, try something like `objdump -t EXECUTABLE | awk 'pass && $3 ~ /F/ { print $5, $6 } /^SYMBOL TABLE:/ { pass=1 }' | sort` (I did say the format was annoying). To enable builtin name demangling in GNU objdump, also pass -C.
I think you can compile both C# and Java to native code entirely (without a self-contained runtime) but it's not the common way to deploy executables written in those languages.
That said, I'm sure there are ways to get these statistics out of a .dll/.jar as well. Reasoning about them may be a little tough as you have no idea if the code will be JIT'ed or evaluated as bytecode until you run the code, but raw bytes on disk shouldn't pose a problem.
Worst case scenario, you can just dump the disassembled bytecode (https://stackoverflow.com/questions/11345034/how-many-bytes-... or https://stackoverflow.com/a/6574882) and start counting. Provided you don't add any native calls, of course, then you'll need to add objdump's transformed output as well.
Analyzing the bytecode can give some insight into how the compiler is likely to treat the code (inlining, intrisics, etc.), of course, so it's not useless, just not the whole story.
And, as you mention, JVM (and .NET) languages can also be AOT compiled. In those cases you could use more standard analysis similar to that in the OP.
The only difference is that AFAIK the languages you cite all have enough runtime information to allow downcasting, which in Rust one has to introduce manually (it is one of the solutions mentioned in the post).