Skip to content

Commit 5d5eecc

Browse files
committed
Demote all headers 1 level
1 parent c353e30 commit 5d5eecc

File tree

1 file changed

+15
-15
lines changed

1 file changed

+15
-15
lines changed

blog/2020/05/invalidations.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ These efforts have met with considerable success: the upcoming Julia 1.5 feels "
1818
But the job of reducing latency is not over yet.
1919
Recently I got interested in a specific source of this latency, and this blog post is a summary of some of what I've learned about the scope of this problem and opportunities for further improvement.
2020

21-
# Method invalidation: what is it and when does it happen?
21+
## Method invalidation: what is it and when does it happen?
2222

23-
## An example: compilation in the presence of Union-splitting
23+
### An example: compilation in the presence of Union-splitting
2424

2525
When Julia compiles a method for specific types, it saves the resulting code
2626
so that it can be used by any caller.
@@ -128,7 +128,7 @@ end
128128

129129
This is [union-splitting], a performance optimization for cases where an object might be of one of several types.
130130

131-
## Triggering method invalidation
131+
### Triggering method invalidation
132132

133133
One point in particular is worth noting: what's up with that final `f(x)::Int` call?
134134
Didn't it already handle all the possibilities?
@@ -208,7 +208,7 @@ If `applyf` is performance-critical, you'll be very happy that Julia tries to gi
208208
But this leaves the door open to invalidation, which means recompilation the next time you use `applyf`.
209209
If method invalidation happens often, this might contribute to making Julia "feel" sluggish.
210210

211-
# How common is method invalidation?
211+
## How common is method invalidation?
212212

213213
Unfortunately, method invalidation is pretty common.
214214
First, let's get some baseline statistics.
@@ -239,7 +239,7 @@ You can see that key packages used by large portions of the Julia ecosystem inva
239239
hundreds or thousands of MethodInstances, sometimes more than 10% of the total
240240
number of MethodInstances present before loading the package.
241241

242-
# How serious is method invalidation?
242+
## How serious is method invalidation?
243243

244244
The next time you want to call functionality that gets invalidated,
245245
you have to wait for recompilation.
@@ -286,7 +286,7 @@ Loading time is somewhat increased by invalidation, but the cost of
286286
first-time usage is typically larger. When possible, it's best to get
287287
the invalidation out of the way before starting your work.
288288

289-
# Can and should this be fixed?
289+
## Can and should this be fixed?
290290

291291
Invalidations affect latency on their own, but they also impact other potential strategies for reducing latency.
292292
For example, julia creates "precompile" (`*.ji`) files to speed up package usage.
@@ -302,7 +302,7 @@ The real question is whether there are *unnecessary* invalidations,
302302
or an unexploited strategy to limit their impact.
303303
Determining the answer to that question requires that we develop an understanding the common reasons for the large number of invalidations listed in the table above.
304304

305-
# An analysis of the causes of invalidation
305+
## An analysis of the causes of invalidation
306306

307307
This section relies on a recent [pull request to Julia][PRJulia] and
308308
the [invalidations branch][PRSC] of [SnoopCompile].
@@ -313,7 +313,7 @@ execute them first.
313313
As we analyze causes of invalidation, you'll note that in some cases we can begin to think about how they might be fixed.
314314
However, we'll save more detailed recommendations for the final section.
315315

316-
## New methods with greater specificity
316+
### New methods with greater specificity
317317

318318
It will be simplest to start with a case we already understand, the `applyf` example above. In a fresh Julia session,
319319

@@ -354,7 +354,7 @@ Perhaps there is no real need to ever call `applyf` with a `Vector{Any}`;
354354
perhaps you can fix one of its upstream callers to supply a concretely-type vector.
355355
In some cases, though, you might really need to call `applyf` with a `Vector{Any}`, in which case the best choice is to accept this invalidation as necessary and move on.
356356

357-
## New methods with ambiguous specificity
357+
### New methods with ambiguous specificity
358358

359359
Now let's try a real-world case, where the outcomes are more complex.
360360

@@ -471,7 +471,7 @@ So we've discovered an easy place where a developer could do something to produc
471471
You'll also notice one example where the new method is *less specific*.
472472
It is not clear why such methods should be invalidating, and this may be a Julia bug.
473473

474-
## Partial specialization
474+
### Partial specialization
475475

476476
If you try
477477

@@ -533,7 +533,7 @@ So here we see that a technique that very successfully reduces latencies also ha
533533
Fortunately, these cases of partial specialization also seem to count as ambiguities, and so if ambiguous matches are eliminated it should also solve partial specialization.
534534
In the statistics below, we'll lump partial specialization in with ambiguity.
535535

536-
## Some summary statistics
536+
### Some summary statistics
537537

538538
Let's go back to our table above, and augment it with "sources" of invalidation:
539539

@@ -558,7 +558,7 @@ In general terms, the last two columns should probably be fixed by changes in ho
558558
The good news is that these counts reveal that much will likely be fixed by "automated" means.
559559
However, it appears that there will need to be a second round in which package developers inspect individual invalidations to determine what, if anything, can be done to remediate them.
560560

561-
# Fixing invalidations
561+
## Fixing invalidations
562562

563563
You may have noticed that two packages, `Example` and `Revise`, trigger far fewer invalidations that the rest of the packages in our analysis.
564564
`Example` is quite trivial, but `Revise` and its dependencies are quite large.
@@ -573,7 +573,7 @@ The success of this effort gives one hope that other packages too may one day ha
573573
As stated above, there is reason to hope that most of the invalidations marked as "ambiguous" will be fixed by changes to Julia's compiler.
574574
Here our focus is on those marked "more specific," since those are cases where it is hard to imagine a generic fix.
575575

576-
## Fixing a case of type-instability
576+
### Fixing a case of type-instability
577577

578578
In engineering Julia and Revise to reduce invalidations, at least two cases were fixed by resolving a type-instability.
579579
For example, one set of invalidations happened because `CodeTracking`, a dependency of Revise's, defines new methods for `Base.PkgId`.
@@ -603,7 +603,7 @@ The other case was similar: a call from `Pkg` of `keys` on an AbstractDict of un
603603
(due to a higher `@nospecialize` call).
604604
Replacing `keys(dct)` with `Base.KeySet(dct)` (which is the default consequence of calling `keys`) eliminated a very consequential invalidation, one that triggered seconds-long latencies in the next `Pkg` command after loading Revise.
605605

606-
## Redirecting call chains
606+
### Redirecting call chains
607607

608608
Let's return to our FixedPointNumbers `reduce_empty` example above.
609609
A little prodding as done above reveals that this corresponds to the definition
@@ -743,7 +743,7 @@ However, it's a bit uglier than the original;
743743
perhaps a nicer approach would be to allow one to supply `init` as a keyword argument to `maximum` itself.
744744
While this is not supported on Julia versions up through 1.5, it's a feature that seems to make sense, and this analysis suggests that it might also allow developers to make code more robust against certain kinds of invalidation.
745745

746-
# Summary
746+
## Summary
747747

748748
Julia's remarkable flexibility and outstanding code-generation open many new horizons.
749749
These advantages come with a few costs, and here we've explored one of them, method invalidation.

0 commit comments

Comments
 (0)