text: If, like me, you’re a commercial aviation otaku, this walkthrough of an enthusiast built 747 cockpit simulator should be highly relevant to your interests.
  Complementary engineering indicators
  Last year I had the opportunity to watch Cat Swetel’s presentation The Development Metrics You Should Use (but Don’t). The information that could be gleaned from just tracking the start and finish date of work items was eye opening. If you’re using an issue tracker this information is probably already (perhaps with some light data munging) available — no need for TPS reports. Additionally, statistics obtained by data mining your project’s issue tracker are, perhaps, less likely to be juked.
  Around the time I saw Cat’s presentation I finished reading Andy Grove’s High Output Management. The hidden gem in this book (assuming becoming a meeting powerhouse isn’t your bag) was Grove’s notion of indicator pairs. An example of a paired indicator might be the number of sales deals closed paired with the customer retention rate. The underling principle being optimising for one indicator will have an adverse impact on the other. In the example, overly aggressive or deceptive tactics could superficially raise the number of sales made, but would be reflected in a dip in the retention rate as customers returned the product or terminated their service prematurely.
  These ideas lead me to thinking about indicators you could use for a team delivering a software product. Could those indicators be derived cheaply from the hand to hand combat of software delivery? Could they be structured in a way that aggressively pursuing one metric would be reflected negatively in another? I think so.
  These are the three metrics that I’ve been using to track the health of the project that I lead.
  - Date; was the software done when we said it would be done. If you prefer this indicator as a scalar, how many days difference is there between the ship date agreed on at the start of the sprint/milestone/whatever and what was the actual date that you considered it done.
  - Completeness; when the software is done, how many of the things we said we’re going to do actually got delivered in that release.
  - Defects reported; once the software is in the field, what is the rate of bugs reported.
  It is relatively easy, for example, to hit a delivery date if you aggressively descope anything risky or simply don’t do it. But in doing so this lack of promised functionality would impact the completeness metric.
  Conversely, it’s straight forward to hit your milestone’s completeness target if you let the release date slip and slip. Bringing both the metics into line requires good estimation skills to judge how much can be attempted in milestone and provide direct feedback if your estimation skills needed work.
  The third indicator, defects reported in the field, acts as a check on the other two. It would be easy to consistent hit your delivery date with 100% feature completion if your team does a shoddy job. The high fives and :tada: emojis will be short lived if each release brings with it a swathe of high priority bug reports. This indicator also tends to have a second order effect, rushed features to meet a deadline tend to generate remedial work in the following milestones, crowding out promised work or blowing later deadlines.
  I consider these to be complementary metrics, they should be considered together, as a group, rather than individually. Ideally your team should be delivering what you promised, when you promised it, with a low defect rate. But more importantly, if that isn’t the case, if one of the indicators is unhealthy, addressing it shouldn’t result in the problem moving to another.
  Internets of interest #14: UNIX v0
  Read more over at the Living Computer Museum’s restoration page.
  Internets of interest: Warner Losh on the first ten years of UNIX
  UNIX turns 50 this year which means 7th edition Research UNIX is that 40.
  Use internal packages to reduce your public API surface
  In the beginning, before the
  go tool, before Go 1.0, the Go distribution stored the standard library in a subdirectory called
  pkg/ and the commands which built upon it in
  cmd/. This wasn’t so much a deliberate taxonomy but a by product of the original
  make based build system. In September 2014, the Go distribution dropped the
  pkg/ subdirectory, but then this tribal knowledge had set root in large Go projects and continues to this day.
  I tend to view empty directories inside a Go project with suspicion. Often they are a hint that the module’s author may be trying to create a taxonomy of packages rather than ensuring each package’s name, and thus its enclosing directory, uniquely describes its purpose. While the symmetry with
  cmd/ for
  package main commands is appealing, a directory that exists only to hold other packages is a potential design smell.
  More importantly, the boilerplate of an empty
  pkg/ directory distracts from the more useful idiom of an
  internal/ directory.
  internal/ is a special directory name recognised by the
  go tool which will prevent one package from being imported by another unless both share a common ancestor. Packages within an
  internal/ directory are therefore said to be internal packages.
  To create an internal package, place it within a directory named
  internal/. When the
  go command sees an import of a package with
  internal/ in the import path, it verifies that the importing package is within the tree rooted at the parent of the
  internal/ directory.
  For example, a package
  /a/b/c/internal/d/e/f can only be imported by code in the directory tree rooted at
  /a/b/c. It cannot be imported by code in
  /a/b/g or in any other repository.
  If your project contains multiple packages you may find you have some exported symbols which are intended to be used by other packages in your project, but are not intended to be part of your project’s public API. Although Go has limited visibility modifiers–public, exported, symbols and private, non exported, symbols–internal packages provide a useful mechanism for controlling visibility to parts of your project which would otherwise be considered part of its public versioned API.
  You can, of course, promote internal packages later if you want to commit to supporting that API; just move them up a directory level or two. The key is this process is opt-in. As the author, internal packages give you control over which symbols in your project’s public API without being forced to glob concepts together into unwieldy mega packages to avoid exporting them.
  Be wary of functions which take several parameters of the same type
  APIs should be easy to use and hard to misuse.— Josh Bloch
  A good example of a simple looking, but hard to use correctly, API is one which takes two or more parameters of the same type. Let’s compare two function signatures:
  func Max(a, b int) int func CopyFile(to, from string) error
  What’s the difference between these functions? Obviously one returns the maximum of two numbers, the other copies a file, but that’s not the important thing.
  Max(8, 10) // 10 Max(10, 8) // 10
  Max is commutative; the order of its parameters does not matter. The maximum of eight and ten is ten regardless of if I compare eight and ten or ten and eight.
  However, this property does not hold true for
  CopyFile.
  CopyFile("/tmp/backup", "presentation.md") CopyFile("presentation.md", "/tmp/backup")
  Which one of these statements made a backup of your presentation and which one overwrite your presentation with last week’s version? You can’t tell without consulting the documentation. A code reviewer cannot know if you’ve got the order correct without consulting the documentation.
  The general advice is to try to avoid this situation. Just like long parameter lists, indistinct parameter lists are a design smell.
  A challenge
  When this situation is unavoidable my solution to this class of problem is to introduce a helper type which will be responsible for calling
  CopyFile correctly.
  type Source string func (src Source) CopyTo(dest string) error { return CopyFile(dest, string(src)) } func main() { var from Source = "presentation.md" from.CopyTo("/tmp/backup") }
  In this way
  CopyFile is always called correctly and, given its poor API can possibly be made private, further reducing the likelihood of misuse.
  Can you suggest a better solution?
  Don’t force allocations on the callers of your API
  This is a post about performance. Most of the time when worrying about the performance of a piece of code the overwhelming advice should be (with apologies to Brendan Gregg) don’t worry about it, yet. However there is one area where I counsel developers to think about the performance implications of a design, and that is API design.
  Because of the high cost of retrofitting a change to an API’s signature to address performance concerns, it’s worthwhile considering the performance implications of your API’s design on its caller.
  A tale of two API designs
  Consider these two
  Read methods:
  func (r *Reader) Read(buf []byte) (int, error) func (r *Reader) Read() ([]byte, error)
  The first method takes a
  []byte buffer and returns the number of bytes read into that buffer and possibly an
  error that occurred while reading. The second takes no arguments and returns some data as a
  []byte or an
  error.
  This first method should be familiar to any Go programmer, it’s
  io.Reader.Read. As ubiquitous as
  io.Reader is, it’s not the most convenient API to use. Consider for a moment that
  io.Reader is the only Go interface in widespread use that returns both a result and an error. Meditate on this for a moment. The standard Go idiom, checking the error and iff it is
  nil is it safe to consult the other return values, does not apply to
  Read. In fact the caller must do the opposite. First they must record the number of bytes read into the buffer, reslice the buffer, process that data, and only then, consult the error. This is an unusual API for such a common operation and one that frequently catches out newcomers.
  A trap for young players?
  Why is it so? Why is one of the central APIs in Go’s standard library written like this? A superficial answer might be
  io.Reader‘s signature is a reflection of the underlying
  read(2) syscall, which is indeed true, but misses the point of this post.
  If we compare the API of
  io.Reader to our alternative,
  func Read() ([]byte, error), this API seems easier to use. Each call to
  Read() will return the data that was read, no need to reslice buffers, no need to remember the special case to do this before checking the error. Yet this is not the signature of
  io.Reader.Read. Why would one of Go’s most pervasive interfaces choose such an awkward API? The answer, I believe, lies in the performance implications of the APIs signature on the caller.
  Consider again our alternative
  Read function,
  func Read() ([]byte, error). On each call
  Read will read some data into a buffer1 and return the buffer to the caller. Where does this buffer come from? Who allocates it? The answer is the buffer is allocated inside
  Read. Therefore each call to
  Read is guaranteed to allocate a buffer which would escape to the heap. The more the program reads, the faster it reads data, the more streams of data it reads concurrently, the more pressure it places on the garbage collector.
  The standard libraries’
  io.Reader.Read forces the caller to supply a buffer because if the caller is concerned with the number of allocations their program is making this is precisely the kind of thing they want to control. Passing a buffer into
  Read puts the control of the allocations into the caller’s hands. If they aren’t concerned about allocations they can use higher level helpers like
  ioutil.ReadAll to read the contents into a
  []byte, or
  bufio.Scanner to stream the contents instead.
  The opposite, starting with a method like our alternative
  func Read() ([]byte, error) API, prevents callers from pooling or reusing allocations–no amount of helper methods can fix this. As an API author, if the API cannot be changed you’ll be forced to add a second form to your API taking a supplied buffer and reimplementing your original API in terms of the newer form. Consider, for example,
  io.CopyBuffer. Other examples of retrofitting APIs for performance reasons are the
  fmt package and the
  net/http package which drove the introduction of the
  sync.Pool type precisely because the Go 1 guarantee prevented the APIs of those packages from changing.
  If you want to commit to an API for the long run, consider how its design will impact the size and frequency of allocations the caller will have to make to use it.
  Go compiler intrinsics
  Go allows authors to write functions in assembly if required. This is called a stub or forward declaration.
  package asm // Add returns the sum of a and b. func Add(a int64, b int64) int64
  Here we’re declaring
  Add, a function which takes two
  int64‘s and returns their sum.
  Add is a normal Go function declaration, except it is missing the function body.
  If we were to try to compile this package the compiler, justifiably, complains;
  % go build examples/asm ./decl.go:4:6: missing function body
  To satisfy the compiler we must supply a body for
  Add via assembly, which we do by adding a
  .s file in the same package.
  TEXT ·Add(SB),$0-24 MOVQ a+0(FP), AX ADDQ b+8(FP), AX MOVQ AX, ret+16(FP) RET
  Now we can build, test, and use our
  Add function just like normal Go code. But, there’s a problem, assembly functions cannot be inlined.
  This has long been a complaint by Go developers who want to use assembly either for performance or to access operations which are not exposed in the language. Some examples would be vector instructions, atomic instructions, and so on. Without the ability to inline assembly functions writing these functions in Go can have a relatively large overhead.
  var Result int64 func BenchmarkAddNative(b *testing.B) { var r int64 for i := 0; i < b.N; i++ { r = int64(i) + int64(i) } Result = r } func BenchmarkAddAsm(b *testing.B) { var r int64 for i := 0; i < b.N; i++ { r = Add(int64(i), int64(i)) } Result = r }
  BenchmarkAddNative-8 1000000000 0.300 ns/op BenchmarkAddAsm-8 606165915 1.93 ns/op
  Over the years there have been various proposals for an inline assembly syntax similar to gcc’s
  asm(...) directive. None have been accepted by the Go team. Instead, Go has added intrinsic functions1.
  An intrinsic function is Go code written in regular Go. These functions are known the the Go compiler which contains replacements which it can substitute during compilation. As of Go 1.13 the packages which the compiler knows about are:
  math/bits
  sync/atomic
  The functions in these packages have baroque signatures but this lets the compiler, if your architecture supports a more efficient way of performing the operation, transparently replace the function call with comparable native instructions.
  For the remainder of this post we’ll study two different ways the Go compiler produces more efficient code using intrinsics.
  Ones count
  Population count, the number of
  1 bits in a word, is an important cryptographic and compression primitive. Because this is an important operation most modern CPUs provide a native hardware implementation.
  The
  math/bits package exposes support for this operation via the
  OnesCount series of functions. The various
  OnesCount functions are recognised by the compiler and, depending on the CPU architecture and the version of Go, will be replaced with the native hardware instruction.
  To see how effective this can be lets compare three different ones count implementations. The first is Kernighan’s Algorithm2.
  func kernighan(x uint64) int { var count int for ; x > 0; x &= (x - 1) { count++ } return count }
  This algorithm has a maximum loop count of the number of bits set; the more bits set, the more loops it will take.
  The second algorithm is taken from Hacker’s Delight via issue 14813.
  func hackersdelight(x uint64) int { const m1 = 0x5555555555555555 const m2 = 0x3333333333333333 const m4 = 0x0f0f0f0f0f0f0f0f const h01 = 0x0101010101010101 x -= (x >> 1) & m1 x = (x & m2) + ((x >> 2) & m2) x = (x + (x >> 4)) & m4 return int((x * h01) >> 56) }
  Lots of clever bit twiddling allows this version to run in constant time and optimises very well if the input is a constant (the whole thing optimises away if the compiler can figure out the answer at compiler time).
  Let’s benchmark these implementations against
  math/bits.OnesCount64.
  var Result int func BenchmarkKernighan(b *testing.B) { var r int for i := 0; i < b.N; i++ { r = kernighan(uint64(i)) } Result = r } func BenchmarkPopcnt(b *testing.B) { var r int for i := 0; i < b.N; i++ { r = hackersdelight(uint64(i)) } Result = r } func BenchmarkMathBitsOnesCount64(b *testing.B) { var r int for i := 0; i < b.N; i++ { r = bits.OnesCount64(uint64(i)) } Result = r }
  To keep it fair, we’re feeding each function under test the same input; a sequence of integers from zero to
  b.N. This is fairer to Kernighan’s method as its runtime increases with the number of one bits in the input argument.3
  BenchmarkKernighan-8 100000000 11.2 ns/op BenchmarkPopcnt-8 618312062 2.02 ns/op BenchmarkMathBitsOnesCount64-8 1000000000 0.565 ns/op
  The winner by nearly 4x is
  math/bits.OnesCount64, but is this really using a hardware instruction, or is the compiler just doing a better job at optimising this code? Let’s check the assembly
  % go test -c % go tool objdump -s MathBitsOnesCount popcnt-intrinsic.test TEXT examples/popcnt-intrinsic.BenchmarkMathBitsOnesCount64(SB) /examples/popcnt-intrinsic/popcnt_test.go popcnt_test.go:45 0x10f8610 65488b0c2530000000 MOVQ GS:0x30, CX popcnt_test.go:45 0x10f8619 483b6110 CMPQ 0x10(CX), SP popcnt_test.go:45 0x10f861d 7668 JBE 0x10f8687 popcnt_test.go:45 0x10f861f 4883ec20 SUBQ $0x20, SP popcnt_test.go:45 0x10f8623 48896c2418 MOVQ BP, 0x18(SP) popcnt_test.go:45 0x10f8628 488d6c2418 LEAQ 0x18(SP), BP popcnt_test.go:47 0x10f862d 488b442428 MOVQ 0x28(SP), AX popcnt_test.go:47 0x10f8632 31c9 XORL CX, CX popcnt_test.go:47 0x10f8634 31d2 XORL DX, DX popcnt_test.go:47 0x10f8636 eb03 JMP 0x10f863b popcnt_test.go:47 0x10f8638 48ffc1 INCQ CX popcnt_test.go:47 0x10f863b 48398808010000 CMPQ CX, 0x108(AX) popcnt_test.go:47 0x10f8642 7e32 JLE 0x10f8676 popcnt_test.go:48 0x10f8644 803d29d5150000 CMPB $0x0, runtime.x86HasPOPCNT(SB) popcnt_test.go:48 0x10f864b 740a JE 0x10f8657 popcnt_test.go:48 0x10f864d 4831d2 XORQ DX, DX popcnt_test.go:48 0x10f8650 f3480fb8d1 POPCNT CX, DX // math/bits.OnesCount64 popcnt_test.go:48 0x10f8655 ebe1 JMP 0x10f8638 popcnt_test.go:47 0x10f8657 48894c2410 MOVQ CX, 0x10(SP) popcnt_test.go:48 0x10f865c 48890c24 MOVQ CX, 0(SP) popcnt_test.go:48 0x10f8660 e87b28f8ff CALL math/bits.OnesCount64(SB) popcnt_test.go:48 0x10f8665 488b542408 MOVQ 0x8(SP), DX popcnt_test.go:47 0x10f866a 488b442428 MOVQ 0x28(SP), AX popcnt_test.go:47 0x10f866f 488b4c2410 MOVQ 0x10(SP), CX popcnt_test.go:48 0x10f8674 ebc2 JMP 0x10f8638 popcnt_test.go:50 0x10f8676 48891563d51500 MOVQ DX, examples/popcnt-intrinsic.Result(SB) popcnt_test.go:51 0x10f867d 488b6c2418 MOVQ 0x18(SP), BP popcnt_test.go:51 0x10f8682 4883c420 ADDQ $0x20, SP popcnt_test.go:51 0x10f8686 c3 RET popcnt_test.go:45 0x10f8687 e884eef5ff CALL runtime.morestack_noctxt(SB) popcnt_test.go:45 0x10f868c eb82 JMP examples/popcnt-intrinsic.BenchmarkMathBitsOnesCount64(SB) :-1 0x10f868e cc INT $0x3 :-1 0x10f868f cc INT $0x3
  There’s quite a bit going on here, but the key take away is on line 48 (taken from the source code of the
  _test.go file) the program is using the x86
  POPCNT instruction as we hoped. This turns out to be faster than bit twiddling.
  Of interest is the comparison two instructions prior to the
  POPCNT,
  CMPB $0x0, runtime.x86HasPOPCNT(SB)
  As not all intel CPUs support
  POPCNT the Go runtime records at startup if the CPU has the necessary support and stores the result in
  runtime.x86HasPOPCNT. Each time through the benchmark loop the program is checking does the CPU have POPCNT support before it issues the
  POPCNT request.
  The value of
  runtime.x86HasPOPCNT isn’t expected to change during the life of the program’s execution so the result of the check should be highly predictable making the check relatively cheap.
  Atomic counter
  As well as generating more efficient code, intrinsic functions are just regular Go code, the rules of inlining (including mid stack inlining) apply equally to them.
  Here’s an example of an atomic counter type. It’s got methods on types, method calls several layers deep, multiple packages, etc.
  import ( "sync/atomic" ) type counter uint64 func (c counter) get() uint64 { return atomic.LoadUint64((uint64)(c)) } func (c counter) inc() uint64 { return atomic.AddUint64((uint64)(c), 1) } func (c counter) reset() uint64 { return atomic.SwapUint64((uint64)(c), 0) } var c counter func f() uint64 { c.inc() c.get() return c.reset() }
  You’d be forgiven for thinking this would have a lot of overhead. However, because of the interaction between inlining and compiler intrinsics, this code collapses down to efficient native code on most platforms.
  TEXT main.f(SB) examples/counter/counter.go counter.go:23 0x10512e0 90 NOPL counter.go:29 0x10512e1 b801000000 MOVL $0x1, AX counter.go:13 0x10512e6 488d0d0bca0800 LEAQ main.c(SB), CX counter.go:13 0x10512ed f0480fc101 LOCK XADDQ AX, 0(CX) // c.inc counter.go:24 0x10512f2 90 NOPL counter.go:10 0x10512f3 488b05fec90800 MOVQ main.c(SB), AX // c.get counter.go:25 0x10512fa 90 NOPL counter.go:16 0x10512fb 31c0 XORL AX, AX counter.go:16 0x10512fd 488701 XCHGQ AX, 0(CX) // c.reset counter.go:16 0x1051300 c3 RET
  By way of explanation. The first operation,
  counter.go:13 is
  c.inc a
  LOCKed
  XADDQ, which on x86 is an atomic increment. The second,
  counter.go:10 is
  c.get which on x86, due to its strong memory consistency model, is a regular load from memory. The final operation,
  counter.go:16,
  c.reset is an atomic exchange of the address in
  CX with
  AX which was zeroed on the previous line. This puts the value in
  AX, zero, into the address stored in
  CX. The value previously stored at
  (CX) is discarded.
  Conclusion
  Intrinsics are a neat solution that give Go programmers access to low level architectural operations without having to extend the specification of the language. If an architecture doesn’t have a specific
  sync/atomic primitive (like some ARM variants), or a
  math/bits operation, then the compiler transparently falls back to the operation written in pure Go.
  Clear is better than clever
  This.
  Sydney High Performance Go workshop
  On the 17th of July I’ll be giving a version of my High Performance Go workshop updated for the upcoming changes in Go 1.13. The event is free, as in puppy, however numbers are limited due to the venue size. The event will be held in the Sydney CBD, the address will be provided to registered attendees closer to the date.
  You can find a link to the workshop description and syllabus here.
  You can find a link to the registration page here.
  No show policy
  If you register for the event then don’t show up you are be depriving someone else of the opportunity to participate. You can cancel you registration at any time up to 23:59 on the 16th. If you are a no show you will be expected to make a meaningful donation to a charity of my choosing.