humancode.us

Always be making

January 13, 2024

Magnetic domains in a ferromagnetic material aligned by an external magnetic field

By MikeRun - Own work, CC BY-SA 4.0

I like to think of myself as a maker. I like to learn skills and construct things. But all too often, I get so discouraged by my daily busyness that I forget to want to make something. When I get an unexpected stretch of discretionary time, I sometimes don’t know what to do with it: I spend it doing random chores, playing games, or just resting—all very good things to do—but I leave a lot of potential on the table.

We often complain we don’t have time to do what we want. But the truth is, even the busiest adult has some time at their discretion; it just comes in tinier chunks. An hour here, 15 minutes there… but taken together, it adds up to a lot. The question is: when one of these precious opportunities falls in your lap, would you know what to do with it?

Read more…

Thoughts on generative AI and responsibility

January 8, 2024

Here’s an illustration of a rudimentary mental model that I use when thinking about advances in computing tools.

x-y graph. The x-axis is “resources” and the y-axis is “skill”. Concentric circles are drawn about the origin in the positive quadrant. The closest to the origin is labeled “Anyone can do it”. The next is labeled “Experts only”, and the last is labeled “Impractical”. A red line shows a dot moving from “Experts only” to “Anyone can do it”.

Computers are already (essentially) Turing-complete, so anything that can be done can in theory already be done using any existing technology. But what these leaps do is that they bring down the skill and resources needed to accomplish a certain task. The red arrow in the image is what such a leap does.

Generative AI is such a leap. The red dot represents not only something genuinely useful that people used to have to learn a skill or pay someone to do, but can now do with ease (removing a distracting object from a photograph), but also vectors of abuse that similarly gain the same level of ease (crafting misinformation, generating fake revenge porn). With every leap, thousands of these red dots move toward the origin, some good for humanity, and others bad.

Read more…

All about libraries

January 3, 2024

After writing the post about mergeable libraries, I thought I should write a post about how libraries work in general, and capture some recommendations on how to use them.

Let’s start at the beginning, with what happens when a source file is compiled.

A compiler creates object files from source files

A compiler takes a translation unit (a source file with any imported headers), and produces a compiled object file, containing the code and data defined in the translation unit.

Exported symbols

An object file may export symbols. Exported symbols are strings that identify data structures within the object file, which may be function implementations, constants, initialized data, whatever.

// sound.c

static int tweetCount = 0;

extern void tweet(void) {
    tweetCount++;
}

The file above compiles into an object file sounds.o which exports the symbol _tweet for the implementation of the tweet() function1 2.

Some symbols are purely internal to the translation unit. tweetCount, for example, is not exported.

In addition to open/public (exported) and private/fileprivate (not exported), Swift symbols have an access control option, package, which makes the symbol visible only within a Swift package. As far as libraries are concerned, package symbols are exported.

  1. By convention, C functions are exported with a leading underscore. 

  2. By default, C symbols are exported unless marked static. You can flip this behavior by setting GCC_SYMBOLS_PRIVATE_EXTERN = YES, and using visibility attributes to export symbols. 

Read more…

Measuring the performance of mergeable libraries in iOS apps

January 2, 2024

I was curious about what the use of mergeable libraries meant for a typical app that may have a lot of library dependencies, so I devised a test which would measure the performance of merged frameworks versus old-school dynamic frameworks.

To read more about how mergeable libraries work, read this post.

The results

Let’s start with the results. These were taken on an iPhone 14 Pro using Instruments.

Graph. X axis shows number of frameworks from 0–100. Y axis shows time to UIKit initialization. First series: “individual frameworks”. The line goes from around 40 ms at zero frameworks, to about 60 ms at one, and rising linearly to just over 600 ms with 100. Second series: “merged frameworks”. The line hovers around 50 ms, and stays flat and rises slightly to just under 100 ms at 100. Third series: “merged frameworks with intermediate non-merged framework”. The line remains about as flat as the second series, but at a slightly higher plateau around 80 ms. The line rises steadily at 70 to reach about 180 ms at 100. Fourth series: static libraries. The line stays flat at around 30–50 ms.

And here is a close-up of the region around the origin:

Close-up of the previous graph around the origin

As you can see, the difference is dramatic. Virtually all of the O(n) cost of dynamic library loading is gone, even when an intermediate merged framework is introduced. It’s almost like the dynamic libraries have been turned into static ones, and that is not far from the truth.

Read more…

All about mergeable libraries

January 2, 2024

Mergeable Libraries is a technology introduced in WWDC23 that allows you to “absorb” and reexport dynamic libraries into a higher-level dynamic library, or directly into your app’s binary.

To see the performance implications of using mergeable libraries in your app, see this post.

How mergeable libraries work

The mergeable libraries feature allows you to copy the contents of dependent1 dynamic libraries one level up while maintaining the illusion in code that the original dependent libraries still existed where they were, when using API such as dlopen and Bundle.

Because the contents of dependent libraries are copied into the binary that links them, unresolved symbols in that binary can be statically resolved against the library’s contents which are now stored within the same binary. This is how mergeable libraries improve load times: it allows the linker to turn load-time resolution of symbols into link-time resolution, giving you dynamic-library semantics with near-static-library performance.

  1. I use the term “dependent libraries” to refer to a library that is linked by another binary, i.e. the child nodes in a link dependency tree. I know this term can be confusing, but this is the terminology Apple uses in their docs. 

Read more…