Skip to content

cmd/compile: specialize instantiations of "certain" generic functions #81955

Open

Description

@mcy

Currently, generic functions are (almost) always shaped when instantiated, regardless of size. Shapes functions get the following overhead:

  1. Dictionary calls: any interface operation has to go through the dictionary, and this costs eight bytes of binary size per itab; any generic call must also have a dictionary entry for its relevant dictionary.
  2. Interface wrappers: interface calls to non-generic methods of generic type need a wrapper to shift the input registers and stick the dictionary in RAX or whatever.

This tradeoff has three benefits:

  1. Improved icache pressure because there are simply less functions. This helps mitigate overhead (1).
  2. Smaller binaries, which means faster link times (some people care a lot about this, although it is hard to know when to justify it over performance -- for the sake of disclosure, I only care about benefit (2) for the sake of (1)).
  3. Faster build times, because fewer functions hit SSA and ultimately produce assembly that the linker has to copy around.

My personal opinions aside (read: I come from C++), this is a pretty sound tradeoff between code density and performance for average code. However, I think we can do better.


A function is specialized when rather than being shaped, a brand new, non-shaped function is stamped "as if it were a macro". Specialization can coexist with shaping in the following way:

  1. shaped -> specialized. Requires a dictionary entry, except that this entry is a function pointer rather than a dictionary entry.
  2. specialized -> shaped. Exactly the same as calling a shaped function from monomorphic code: static call + pc-relative load of the dictionary.

So the question is, when do we specialize[1]? I am interested in investigating the following:

  1. Specialization of small functions (say, inline cost <80 or <40), especially those which only call other specialized functions.
  2. "Hot" functions, as reported by PGO. PGO does not currently record tparams of profiled functions, although we could, in theory, reconstruct this from the symbols of monomorphic functions called through a dictionary.
  3. Known-hot generic functions in the standard library, via a standard-library only //go:specialize pragma.

(1) and (3) are the easiest to investigate; (3) seems like it will have the easiest wins per code bloat (for example, specializing slices.Sort for ints and strings).

I do not know of any issues that are precisely about this topic, although #48849, #75056 appear relevant? I plan to investigate these avenues and get some performance numbers to see if there is some sensible middleground.

[1]: @dr2chase told me some time ago that "there is some function somewhere in the compiler for forcing specialization of an ir.Func given tparams", but I can't find such a thing. Perhaps it got ripped out.

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.Performancecompiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions