Are there any tools that help finding these kinds of things? Like a profiler that says "80% of the allocated bytes are objects of this type, with 95% of those having that field set to None"
It would be super useful since I think this is pretty likely to be surprising to many users. But the profiler would need to be a particularly-specific refinement of even that: you need to make it obvious that it's not "95% of your Option<Thing>s are None, and your Option<Things> are using X bytes", but that "95% of the bytes used for your Option<Thing>s are used for None versions." Otherwise you could just assume that your non-None ones are just that chunky, or you have that many of them... I haven't seen a profiler with that level of insight, unfortunately.
Perhaps because this feels like a fairly rust-specific gotcha. Especially if you're coming from languages where there's often not much syntactical distinction made between "this is a pointer because I don't want to be copying it" and "this is a pointer because it's optional."
For instance, it's not until now that I actually understood what the sibling comment about the Enum type size discrepancy lint meant: "This lint obviously cannot take the distribution of variants in your running program into account. It is possible that the smaller variants make up less than 1% of all instances, in which case the overhead is negligible and the boxing is counter-productive. Always measure the change this lint suggests." I had always accidentally read this backwards, thinking it meant something more to the effect of "if most of the instances are actually small, then it's not a problem here, but be aware that some of them are much larger so some of your calls to things with this could end up passing much larger types."
That may be surprisingly difficult in Rust. We generally think of Option<T> using O to represent None. However, it can actually use any invalid value of T
For example None of Option<OwnedFd> is the bit pattern for the integer -1, the invalid Unix file descriptor
And in this particular context None of Option<CompactString> is the bit pattern for a carefully chosen impossible 24 byte slice, all zeroes is of course a completely valid way to spell 24 of the ASCII NUL U+0000 character so we can't use that to signify None, but many 24 byte slices are not valid UTF-8 encodings.
When some day I get to make my own BalancedI8 in stable Rust (the 8-bit signed integer except without the slightly annoying and rarely needed most negative value -128) then None of Option<BalancedI8> will occupy the bit pattern for -128 which is 0x80
So, the long answer with lots of reading material is that you want "Pattern Types" and who knows when that could land in Rust. Pattern types are a simple Refinement Type, you can go absolutely wild with refinement in theory and some niche languages go much deeper but all we want here is to say "Only these values of the type are allowed" and by implication all bit patterns not used for those values are a niche and Rust would optimise accordingly.
Rust doesn't (even unstably) have Pattern Types so you might wonder how NonZeroU32 works for example, or indeed OwnedFd, and similar types. For these types there's a permanently unstable "compiler only" feature flag which allows you to explicitly specify the niche, that's how they're made. So, if you're comfortable writing unstable nightly-only software you can do this today, go look at the guts of NonZeroU32 for example.
If you want to write Rust software for ordinary people who use stable Rust you have two options today and for the indefinite future in which Pattern Types are not stable:
1. Enumerations: An enumeration which has say 5 values clearly doesn't need byte values 0x5 through 0xFF, so Rust stably promises this is a niche. For BalancedI8 that's kinda messy with 255 values but tolerable, some real crates use this trick or one related to it and they work fine - for a hypothetical BalancedI16 it's imaginable to create 65535 values but silly, and for BalancedI32 clearly we should not expect the compiler to accept an enumeration with 4 billion+ named values so no...
2. XOR trick: Rust provides NonZeroI8 for example. We can "make" BalancedI8 by providing accessors which always XOR -128 (0x80) with the value and then actually internally we store the NonZeroI8 instead, at runtime now operations incur an extra XOR which is a very cheap ALU operation. This works for any "Not this" value because of the properties of the XOR operation, so unlike with enums this is practical for BalancedI64 for example.
There is nook which does it with unstable features [1] and nonany [2] which uses xor operations to map your custom niche value to 0 so it can use the NonZero* types to achieve the same in stable rust.
Eventually rust will likely gain pattern types as a more generally useful version of the features used in nook. There is even some actively ongoing work on this [3]
Niche values: fair! You can't just scan memory looking for 0000000000... (... for some types at least)
But if a debugger can show you all values of type X, and the compiler defines null-y values of X, surely there's some way? That still doesn't seem complicated, just not as overwhelmingly-trivial as some languages.
The closest I am aware of is clippy (`cargo clippy` in a standard Rust project will run it with default configurations).
Clippy is essentially a linter; and one of its checks catches cases where different enum variants have a significantly different size; with a suggestion to Box the larger variant.
Since this is just a linter, it doesn't actually have any knowledge of how frequently each variant is actually used. It also doesn't address the situation in the article at all.
I've personally found heaptrack[1] pretty good for this task, very straightforward to use and the info is detailed enough. Though, it'll only tell you where they are happening (e.j. allocation rate for Box::new), but not exactly what type they are given that info isn't available at runtime. Usually that kind of thing would be reserved to GC-based languages where they keep track of counts for each object.
You can expect some blog posts from us on this topic at the end of the year / early next year. In short: Organizational focus on a performance target, significant investment, and some great new tooling. We're also reaping the benefits of foundational work that happened over the last few years.
I've found two examples of DWARF expressions in the wild: 1. A handwritten expression in libpthread <= 2.19, which was removed in 2014 [1], and 2. the expression covering the PLT section of most binaries. [2]
It works with optimized builds, and it works better with them than gdb does.
When you debug an optimized build with debug info in gdb by stepping line by line, it is easy to accidentally step "too far" and completely lose your place. In rr, you can always step back and recover.
For people who are experiencing a leak on macOS 12: Check if you have set a custom cursor color in the system accessibility preferences. Resetting the cursor color to the default may fix it.
Having worked at Apple adjacent to the likely responsible teams, the relevant details are: overworked engineering teams, insufficient QA investment, and most of all a yearly macOS major release schedule that persists primarily to benefit the egos of Apple's upper management.
Until you see a WWDC that doesn't announce a major release of macOS, expect more of the same.
To any involved Apple folks here, I feel your pain, and I'm sorry.
And this is why I have completely stopped using all Apple products. I used to be a massive Mac fanboy. But the software quality is absolute shit now and has been for at least the past 5 years. I don't understand why anyone puts up with it.
I've been seeing this exact same comment for over a decade now.
The first couple of releases of OSX are always a little rough around the edges. And then by the end of the cycle everyone proclaims how wonderful this release is.
Except the bugs have continued to get worse and worse. For me the deal breaker was the blank page in iOS Safari[1]. After fighting that one constantly, I threw in the towel. I've been so much happier. Btw I was an Apple user from System 7 through to 2019.
Back in the days OS X was a dumpster fire in terms of overall reliability until the very late releases of every major version. Some versions like Lion had pure crashes until the end.
Even looking a few years before, we had the root user password bug and other pretty severe issues way worse than what we’re seeing now.
I did say over the past 5 years, so things like the root password issue I include in that. I'm also utterly convinced airdrop is just a long running joke at Apple, I've gotten it to work like twice.
Snow Leopard was as solid as OSX ever got in my estimation. Man I miss those days. Snow Leopard's primary goal was just to harden Leopard and not really have too many new features. Apple really needs to bring that kind of thinking back. I'm happy to see their hardware is back on track, now if they could just get the software to do a U turn...
I speak only for myself, but after Catalina I started transitioning to Linux and couldn't be happier. Being able to set up my entire computer with a single Github repo is a godsend for productivity, all it takes are a few keystrokes and I've got a fully configured desktop with all my dotfiles, keybinds and applications.
I've been a Linux user for some 10 years, but have also had to use a Macbook Pro for a while due to work. There's nothing stopping you from fully configuring macOS through a single repository similar to how you do Linux. For a while my dot files were aimed at Linux (primarily), macOS, and Windows as I anticipated to have to use both macOS and Windows down the line, though I've since removed much of the multiplatform code.
Things may be different now as I haven't used a mac since about 2015, but depending on what tools you needed you couldn't escape the GUI completely (for a fully automated setup). At this point I don't remember all that was wrong, but one of the biggest required installing xcode or something like that before I could get git to work.
You don't even need --cask anymore. You can also use `brew bundle dump` to synchronize what you've installed via brew, and it also can sync mac app store installs too.
It's a bit annoying getting macOS system preferences synced still although.
How are you managing the desktop (gnome) files? I swear every time I try to move them to a new system or account all I get is grief; weird bugs, application crashes, dbus weirdness. I would love to see your recipe :) . All I can usually do is bring over app config files like emacs/vim/etc/personal scripts.
I don't use GNOME on any of my systems anymore (the 40 update destroyed all hope I had for the desktop going forwards), but I'm convinced you can get some settings transferred by poking around in your ~/.local directory. Having written a few GTK applications in the past, it seems like the rationale for this is because of GNOME's settings API, and how they define compliance with the GNOME spec. I find it to be a total clusterfuck, and if I had any confidence in the desktop's current management team I'd probably open a few pull requests/RFCs to try and fix it. I might sound a little heavy-handed here, but the "my way or the highway" rhetoric that GNOME's developers are pushing right now makes it really hard for me to take their desktop seriously, or blame anything but the developers themselves for their lack of features.
In any case, I can assure you that behavior is perfectly "normal" to them, unfortunately.
That sounds really neat is it some thing you can share? I recently setup a new machine which didn't take very long, but I have run into a few things I forget so would like to set up something similar.
I basically just run an install script which does a few different things. I start by updating the repos and regenerating my mirrors so I get the fastest downloads possible. After that, I install shell utilities (my editor, shell of choice, base-devel, etc.) and then I enable the AUR so I can grab the rest of my desired apps. The rest of it is decidedly basic, it just copies my tracked config files to ~/.config/ and moves my wallpaper to /usr/share/wallpapers. I run a few rain dances automatically too, like `sudo chmod a+wr /opt/spotify` (which lets me automate my Spotify theming process) and installing/unzipping a Steam theme.
To install, I run `git clone https:github.com/username/repo && ./repo/install.sh`, and I'm off to the races. I really reccommend writing one for yourself, as it's a great way to learn shell scripts.
For me there's a trade-off, depending on how often I setup a new machine. Value of automating with a procedural script vs taking the opportunity to try a leaner (or more modern) toolchain.
Currently upgrade about every 2-3 years, so I do tend not to need a bunch of things each iteration, and might upgrade OS. But I'd like a backup in case e.g. hardware failure, laptop lost or stolen.
Some declarative workstation config like terraform or Ansible would be interesting.
What I don't get about apple, with a compensation policy that is less than the other big techs, because they can't get over the late 90s, team sizes that are usually smaller and being one of the largest market cap companies in the world, why don't they hire more?
Hiring more people isn't going to make them more money. Improving their products/services isn't going to make them more money. Providing more value to customers isn't going to make them more money.
Charging $300 for a screen replacement will make them more money. Selling bluetooth headphones with non-replaceable batteries will make them more money. Collecting taxes on developers will make them more money. etc etc
They got popular because of their commitment to quality. "It just works" is and in many ways still is a key to their popularity. They whittle away at their "quality credit rating" the less and less they invest in these things, until their quality credit rating becomes low enough for a competitor exploit that and make them lose market share very quickly. It does make them money.
I can see the business side of the permanent upgrade hype, constant new features, etc. But aren't we supposed to be reaching some kind of detente with Apple where they realize that power users drive the Mac market, and the release schedule should be built around hardware and stability, rather than endless retreads and new consumer features we'll never use? I'm still on El Capitan and pretty much everything since then looks like bloat to me.
You're right, I've just checked and when I set my cursor to be a custom color in accessibility settings suddenly my Firefox started to eat up memory as crazy :D. This went away as soon as I reset the cursor to default colors.
APIs for partial compositing in combination with hardware accelerated compositing was the thing that was missing. If you don't use hardware accelerated compositing, repainting only part of the window, and letting the system compositor know about those areas, is not a problem. It's only the GPU acceleration and the lack of convenient APIs that makes this a problem.
Before Firefox got hardware acceleration, so up until Firefox 3.6, we were using CPU-side painting and sending accurate dirty areas to the windowing system. With Firefox 4, we added hardware accelerated compositing, which made scrolling and transform / opacity animations a lot more performant. However, it also meant that we switched to using OpenGL for the compositor, and macOS does not expose any APIs for invalidating only parts of an OpenGL context. And at the time Firefox 4 shipped, "retina" displays were not a thing yet, so the impact of recompositing the entire window was not apparent. And there was the pervasive notion that "modern GPUs are fast, fill rate is not a problem". It was only as pixel count grew and grew that this started becoming problematic. And it took some amount of research and a lot of surgery to switch Firefox to an approach that gets OpenGL content to the screen while also allowing for partial updates of that OpenGL content.
I couldn't find an API for it, but some Apple apps do in fact do this. I've seen three examples of it:
- Media playback: When a song or a video is playing in a background app, there is an extra button in the system button part on the right that lets you access a media control strip. From it you can pause the current video / audio and even scrub through it.
- Xcode debugging: While Xcode is attached to a running process, there's a button in the system button part on the right side of the touch bar lets you access a debugging control strip, which lets you pause execution and step through the program. This access button is actually in the same place as the media control button, and in cases where both would be shown, the media control button wins.
- QuickTime screen recording: When you start recording the screen from QuickTime, the current recording time + a stop button is displayed in a touch bar overlay even if you focus a different app. However, once you do switch to a different app, you can close the overlay, and it minimizes into that same button slot on the right of the touch bar.
It surely would be nice to be able to do these things without private APIs, but I couldn't find anything so far.