[HN Gopher] Zig Profiling on Apple Silicon
___________________________________________________________________
Zig Profiling on Apple Silicon
Author : signa11
Score : 87 points
Date : 2025-07-29 02:15 UTC (2 days ago)
(HTM) web link (blog.bugsiki.dev)
(TXT) w3m dump (blog.bugsiki.dev)
| turnsout wrote:
| This is cool! I'm anxious to dig into Zig on an M1, and this
| helps.
|
| Side note, the CSS is broken for me in Safari--I get this error:
| Cannot load stylesheet https://blog.bugsiki.dev/assets/css/styles
| heet.b609c58d5c11bb90b1a54e04005d74ad1ddf22165eb79f5533967e57df9c
| 3b50.css. Failed integrity metadata check. Content length: 4943,
| Expected content length: -1, Expected metadata:
| sha256-tgnFjVwRu5CxpU4EAF10rR3fIhZet59VM5Z+V9+cO1A=
| christophilus wrote:
| Mostly unrelated, but I recently built a small utility in Zig,
| Hare, Go, Odin, and V.
|
| I never completed the Odin / V implementations since their
| standard libraries didn't have argon2 (a requirement for me).
|
| Of the group, I liked Odin's syntax and feel best. Hare was also
| very nice. But Zig's optimized binary sizes were unbeatable. 96KB
| vs 500KB for Hare and 2.5MB for Go.
|
| Zig's standard library and tooling are impressive. Personally, I
| wish more projects were written in Zig instead of Rust since Zig
| doesn't seem to have the package explosion problem that Rust has.
| Arnavion wrote:
| There isn't anything fundamental about Zig that makes it immune
| from package explosion. It simply isn't popular and stable
| enough for that to have happened yet.
| conradev wrote:
| Zig's standard library is structured so that you only compile
| what you need, so Zig has no problems adding richer
| functionality to its standard library. This is influenced by
| Zig's decision to only have a single compilation unit per
| compile.
|
| HTTP, for example, can go into Zig's standard library,
| whereas C or Rust cannot do that. This helps control package
| explosion.
| sionisrecur wrote:
| As far as I know rust has dead code elimination. Is the
| problem that compilation takes longer?
| Arnavion wrote:
| The reason Rust doesn't have those things in libstd is
| because it doesn't want to commit to backward compatibility
| for them. Note that Rust is 1.0 and has no plans to switch
| to 2.0.
|
| Zig will presumably have the same care about backward
| compatibility once it becomes stable.
| SkiFire13 wrote:
| On this topic, Rust just added an (unstable for now) option
| to delay codegen until needed https://blog.rust-
| lang.org/inside-rust/2025/07/15/call-for-t...
|
| Just like Zig's decision it is a double edged sword: on one
| side you can avoid compiling code that will not be needed.
| However on the other side you make incremental compilation
| worse, since you will have to recompile it more often.
|
| > HTTP, for example, can go into Zig's standard library,
| whereas C or Rust cannot do that.
|
| Rust _could_ put HTTP in the standard library, the dead
| code would simply be removed when linking. The reason it's
| not in the stdlib has more to do with the fact that:
|
| - it would need to be supported by a team that's already
| overworked - it would need to be supported indefinitely, so
| it would have to be the right interface on the first try.
|
| This effectively prevents any big and complex feature from
| making to the Rust stdlib.
|
| > This helps control package explosion.
|
| Arguably it helps controlling the number of "packages", but
| not the amount of code in those packages. If I split a
| "package" in 4 crates in Rust to get better compile times
| it's still mostly the same code, but you now see a number 4
| times bigger.
| BrouteMinou wrote:
| And potentially, 4 times the number of different authors,
| and 4 times the supply chain attack potential.
|
| It's not just about the number of bytes.
| conradev wrote:
| It's funny because the biggest impact in my eyes is
| social and not technical: the standard library is
| controlled by project governance whereas libraries are
| not.
|
| Zig moves fast with it's BFDL structure, Rust moves slow
| with its committees, and both are by design. I'm excited
| to watch the Zig standard library evolve quickly,
| especially once the language has settled things like I/O.
| mananaysiempre wrote:
| > HTTP, for example, can go into Zig's standard library,
| whereas C or Rust cannot do that.
|
| Yes they can? If you look at old-timey C libraries, for
| example (standard or otherwise), you'll see that they have
| the relatively awkward structure of one public function per
| file. That's an adaptation for static linking, which only
| pulls in the object files that contain symbols required by
| the program, thus it's beneficial to make the object (and
| therefore source) files as small as possible. Yes, the
| compiler still needs to produce of these object files, but
| unlike with Zig it only needs to do so once per (separately
| compiled) library.
|
| An inferior emulation of the same trick, popular in the
| embedded community, is passing --gc-sections to ld, but
| unless you're very careful something will fall off that you
| weren't planning on. (Of course C++ makes things more
| complicated, as always, so you may be forced to use this
| option.)
|
| Glibc's (and specifically Drepper's) aversion to static
| linking did us all a disservice by making static libraries
| less popular.
|
| This does not mean that there isn't some benefit to whole-
| program compilation. E.g. GCC can derive assumptions about
| a non-exported function's arguments and propagate them into
| the function's body even if it does not decide to inline it
| (look for "constprop" symbols in objdump). So that's also a
| thing that people do, in particular in gamedev where the
| somewhat stylized source code structure it requires is less
| of a problem. (Game developers confusingly call this a
| "unity" build--personally I prefer the term "amalgamation"
| used by Lua and SQLite.)
| Someone wrote:
| > Zig's standard library is structured so that you only
| compile what you need,
|
| > so Zig has no problems adding richer functionality to its
| standard library.
|
| That's orthogonal to both
|
| - whether to compile from source in every compilation unit
| or to compile once, and use (shared) libraries,
|
| and to
|
| - whether to provide the standard library as a single unit,
| as is typically done in C, where it is a (shared) library,
| or as multiple interdependent smaller units as in Zig,
| where the standard library contains multiple source files.
|
| > HTTP, for example, can go into Zig's standard library,
|
| The claim "you only compile what you need" also is
| incorrect. Zig's source files (luckily) aren't fine-grained
| enough to support that.
|
| For example, https://github.com/ziglang/zig/blob/master/lib
| /std/http/Clie... contains stuff that not every user of
| that module will need, for example connection pools and a
| function to flush a buffer.
|
| The compiler may not generate code for such unused
| definitions, but it has to parse them, if only to figure
| out where the next definition starts.
| ozgrakkurt wrote:
| I guess the difference is zig doesn't even properly type
| check a function if you didn't use it. Whereas rust
| relies on the linker to remove machine code after that
| code went through the entire compiler pipeline.
|
| Zig not even type checking some code when compiling felt
| a bit off but now I just try to make sure all code is at
| least being smoke tested, so I don't get random
| compilation errors down the line
| CJefferson wrote:
| Why do you think Zig won't have the same issue? In my
| experience lack of packages seem to come from no standard place
| to put them (C++, then you end up with effective package stores
| like Boost), or just not popular enough.
|
| Most languages I work on (Rust, Python, JavaScript, Haskell),
| have a huge number of packages.
| treyd wrote:
| I think that the "package explosion problem" actually does
| exist in C/C++ and Go but it's just hidden. Very often a
| project takes the form of various components, and you only
| depend on a subset of them. In these older-style languages
| these are all shipped as a single unit, but in newer
| languages these are shipped more explicitly so you can see
| what the shape of your dependency tree really looks like.
|
| Boost is a great example of this, since it does a ton of
| different things, but the boundaries between components are
| not quite as obvious as having a "dependencies.lock" to look
| at. Tokio has a ton of different packages but often you only
| need a few of them.
| SkiFire13 wrote:
| Also often dependencies can be hidden by depending on a
| single system library, but that then internally contains a
| ton of stuff. Let's be real about dependencies:
| https://wiki.alopex.li/LetsBeRealAboutDependencies
| kbolino wrote:
| The other thing, which is also a double-edged sword, is
| that "system dependencies" on Linux (generally) have only
| one version installed at a time and that version is
| expected to be suitable for all dependents. Distro
| managers/packagers often put in nontrivial work to make
| this happen. So you often install something new with few
| apparent dependencies because the rest are already
| installed. With dependency locking in Rust etc., you'll
| often "re-"install the same package many times because
| the version is slightly different than what you already
| had.
| dragonelite wrote:
| Its was so nice to just quickly write up a static file server.
| Just to play with wasm without needing to use the usual python
| http server thingy.
|
| I was told the std.http.* isn't meant to be used for production
| servers but its nice that i now have a drop in zig file that
| contains a very very... bare bones static file server i can add
| to zig projects that might need it.
| saagarjha wrote:
| Just use Instruments. Yes, I know it's slow, but it's miles ahead
| of anything on Linux. If you're looking for an identical
| profiling experience on macOS as you get on Linux you're greatly
| missing out.
| ForLoveOfCats wrote:
| XCode is painful but I always miss Instruments whenever I'm
| profiling something on my Linux systems
| verte_zerg wrote:
| What kind of extra functionality are you getting from
| Instruments that isn't covered by other tools?
| dagmx wrote:
| Other than just the niceness of the interface, a key one is
| that the M4 generation added profiling of CPU branching and
| afaik instruments is the only thing that supports it right
| now
| verte_zerg wrote:
| In the M4, Apple mostly added counters only for the SME
| engine. The full list of supported counters can be found in
| the official guide:
| https://developer.apple.com/documentation/apple-
| silicon/cpu-...
|
| Regarding branch profiling, all arm64 (M1+) cpus support
| these counters: - BRANCH_CALL_INDIR_MISPRED_NONSPEC -
| BRANCH_COND_MISPRED_NONSPEC - BRANCH_INDIR_MISPRED_NONSPEC
| - BRANCH_MISPRED_NONSPEC - BRANCH_RET_INDIR_MISPRED_NONSPEC
| - INST_BRANCH - INST_BRANCH_CALL - INST_BRANCH_COND -
| INST_BRANCH_INDIR - INST_BRANCH_RET - INST_BRANCH_TAKEN
|
| afaik there is no limitation to implementing the fetching
| of all these counters based on ibireme's research on kperf.
| btw, forked "poop" already can fetch
| BRANCH_MISPRED_NONSPEC.
___________________________________________________________________
(page generated 2025-07-31 23:01 UTC)