Errata

Efficient Go

Errata for Efficient Go

Submit your own errata for this product.

The errata list is a list of errors and their corrections that were found after the product was released. If the error was corrected in a later version or reprint the date of the correction will be displayed in the column titled "Date Corrected".

The following errata were submitted by our customers and approved as valid errors by the author or editor.

Color key: Serious technical mistake Minor technical mistake Language or formatting error Typo Question Note Update

Version Location Description Submitted By Date submitted Date corrected
Page xvi
Acknowledgments section, 3rd paragraph

Surname typo. It is "Juraj Michalak", should be "Juraj Michalek".

Bartlomiej Plotka  Dec 06, 2022 
Page Chapter 4
Assembly Section

From reader (Victory) who found small bug: The command to get the assembly code for the Go code example `go tool objdump -s <binary>` is supposed to be `go tool objdump -S <binary>`.

Note from the Author or Editor:
Multiple mentions on 117 page (print version)

Bartlomiej Płotka  Mar 23, 2023 
Page Chapter 10
Summary (number 3)

The third summary stated that there is small segment in the flame graph that is `ioutil.ReadFile`. I was analyzing the fgprof.pprof file, but that segment is not `ioutil.ReadFile` it is `os.ReadFile`.

The sum example actually uses `os.ReadFile` not `ioutil.ReadFile`, maybe something changed in the go runtime. I use go1.20.5

Note from the Author or Editor:
Ah great point! The reason is that ioutil.ReadFile was (and still is) available in older Go versions. Now it's deprecated and moved to os.ReadFile. We updated example code, but not profiles, and it's exactly the same code, just moved.

Will try to update profile in the next errata! Thanks.

Victory  Jul 13, 2023 
Page Logging
11th paragraph.

I see the word Structure logic, are you referring to Structured log?

Note from the Author or Editor:
Yes, will clarify in errata, thanks!

Nao Yonashiro  Sep 28, 2023 
Page p.93
1st line

> That means approx 100 million unsigned 8-byte integers.

uint8 is an 8-bit value, so wouldn't this description also be an 8-bit integer?
Therefore, the calculations for memory size following this may also be based on 8 bits.

Note from the Author or Editor:
The math was wrong. On top of that the results from benchmark are hard to explain as the existing JPEG compression format and implementation is much more complex in implementation than just bunch of integers for each pixels. There is stride mechanism (https://medium.com/@oleg.shipitko/what-does-stride-mean-in-image-processing-bba158a72bcd) and progressive JPEG algorithms (https://bitbanksoftware.blogspot.com/2020/08/optimizing-jpeg-decoding.html) in play.

Thanks for noticing! I will change this example to something less tricky!

Anonymous  Oct 06, 2023 
Page p.149
2nd paragraph

> MOVQ <destination register> <address XYZ>
Doesn't the MOVQ instruction in Go asm copy the value at the first address to the second register?

Note from the Author or Editor:
Great point. Actually order of operands differ across standard. Given I was showing Go assembly, you are right, it makes sense to switch it (:

Anonymous  Oct 06, 2023 
Page p.165
last paragraph, numberd list item 1

> ls -l /proc/$PID>/map_files

Wouldn't this command originally look something like the following?

ls -l /proc/$PID/map_files

Note from the Author or Editor:
Yes, thanks for finding this!

Anonymous  Oct 06, 2023 
Page p.19
1st paragraph

In this paragraph, you mentioned that the wasted memory size is 10 TB. However, it seems like there might be a typo in your calculation. 1MB * 100 times * 100 desktops, it would actually amount to about 10 GB, not 10 TB. Is that correct?

Note from the Author or Editor:
Yup, I simplified this sentence in errata. Thanks!

Anonymous  Oct 30, 2023 
Page page 124
numbered list 1

> os.ReadFile and bytes.Split are short enough, so the compiler can copy the
whole body of the Sum function.

Wouldn't it be correct for ’whole body of the Sum' to be '... to the Sum' in this sentence?

Note from the Author or Editor:
Nice catch! I would rather say "os.ReadFile` and `bytes.Split` functions are short enough, so the compiler can copy their whole body to the `Sum` function."

Thanks!

Anonymous  Oct 31, 2023 
Page Page 336
numbered list 4

> we create 110 files using methods...

In list 9-2, we generate 112 files using the append, OpenSingleFile, OpenTenFiles, and Open100FilesConcurrently methods. Is this correct?

Note from the Author or Editor:
That's correct -- even profile shows that... (: Fixed in errata, thanks!

Anonymous  Nov 01, 2023 
Page page 401
example 10-9

The filenames in the prompt (v1.txt, v2.txt, v3.txt) do not match the output. Which one is correct?

Note from the Author or Editor:
Yup, thanks! Clarified that and in Example 10-14

Anonymous  Nov 02, 2023 
Page Page 46
1st list item, end of description for go fmt

> ... You can also install an extended official formatter.

I've never heard of an official tool like this, could you please tell me which one it is?

Note from the Author or Editor:
Great catch thanks! It's the editor mistake, this sentence should be joined with last bullet, so:

"You can also install an extended official formatter called https://oreil.ly/6fDcy[`goimports`] that additionally cleans and formats your import statements."

.. I meant goimports (:

Thanks! will be fixed in the next errata.

Anonymous  Nov 05, 2023 
Page Page 435
footnote 9

> Yes! If we don’t invoke the returned context.CancelContext function, ...

'CancelContext' is a typo for 'CancelFunc' ?

Note from the Author or Editor:
Correct!

Anonymous  Nov 05, 2023 
Page page 439
numbered list 1

> One doing net/http.(*persistConn).writeLoop
> The second doing net/http.(*persistConn).readLoop,...

It seems that the implementation of persistConn is missing in the sample. Should I assume that the leak is occurring inside each method?

Note from the Author or Editor:
Great question. Those are internal HTTP methods.

Clarified this sentence with:

"...is wrong because it leaks two goroutines inside the HTTP library code stuck at `net/http.(*persistConn).writeLoop` and `net/http.(*persistConn).readLoop` respectively. This is confirmed by running `BenchmarkClient` with the `goleak` (those two internal methods will appear in the `goleak` test failure log)."

Anonymous  Nov 05, 2023 
Page 52
at the very bottom

In the numerous bullet point #1, it says:

> Variables a, b, and c are not used, so they cause a compilation error.

However, variable c is used for the initialization of variable d in example 2-7. As the code comment says, the variable not used here is d.

Note from the Author or Editor:
Yes, it should be "Variables a, b and d are not used."

Thanks!

Yoshi Yamaguchi  Jan 11, 2023 
Page 61
first bullet point in #3

> Use the value receiver (no func (g Group) SomeMethod()) if your method does not modify the Group state.

"No" just before `func` doesn't make sense here. I assume this should be "e.g." like what in the second bullet point. (i.e. this part is going to be "e.g. func (g Group) SomeMethod() )

Note from the Author or Editor:
Yes, it should be "e.g.," instead of "no"


Thanks!

Yoshi Yamaguchi  Jan 13, 2023 
Page 66
2nd last paragraph

> Make sure you try writing your own basic Go program, write a unit test, and use loops, switches, and concurrency mechanisms like channels and routines.

The last word "routines" should be "goroutines".

Note from the Author or Editor:
Correct, thanks!

Yoshi Yamaguchi  Jan 14, 2023 
Page 101
footnote #16

> This is a quite powerful thought. For example, imagine you have your application returning a result in 10 m. Reducing it to 1 m by optimizing on one level (e.g., an algorithm) is a game changer.

Are these "m"s (i.e. 10m and 1m) meaning "millisecond" or "minute"?

Note from the Author or Editor:
I meant minutes. However it would be more realistic if we switch to "seconds". So all "m" here, should be changed to "seconds". Thanks!

Yoshi Yamaguchi  Jan 18, 2023 
Page 116
2nd paragraph

> we have sixteen 64-bit general-purpose registers referred to as RAX, RBX, RDX, RBP, RSI, RDI, RSP, and R8-R15.

RCX is not listed here.

Note from the Author or Editor:
Correct, should be RAX, RBX, RCX, RDX, RBP, RSI, RDI, RSP, and R8-R15

Yoshi Yamaguchi  May 08, 2023 
Page 124
the first paragraph (bullet point)

> -gcflags="-m=<number> builds the code while printing the main optimization decisions

I think the closing double quotation is missing; i.e. the option should be -gcflags="-m=<number>".

Yoshi Yamaguchi  Jan 22, 2023 
Page 152
last paragraph (2nd bullet point)

> Our Go program is executing slower than usual, while the memory usage is higher than average. Spoiler: our system might be under memory pressure causing trashing or swapping, as explained in “OS Memory Mapping” on page 168.

The term "trashing" is new to me. I tried to find its definition in the book and on the internet but I couldn't. Could you share the pointer for that?

Note from the Author or Editor:
Totally, thanks for pointing, fixing by adding definition of trashing with my own words. https://en.wikipedia.org/wiki/Thrashing_(computer_science) is a solid explanation, just a bit broader.

Yoshi Yamaguchi  May 09, 2023 
Page 198
Definition of Push/Pull based system

The title of the collection models have been swapped. The first one should be Pull and the second one Push

Note from the Author or Editor:
Wow, interesting how this happened (post production?). Anyway, thanks a lot for noticing. You are totally right.

Ivo G.  May 25, 2023 
Page 200
After bullet point 2

It should be doOperation instead of cooperation function

Note from the Author or Editor:
Great finding thanks!

Anonymous  May 25, 2023 
Page 228/229
Bullet points explaining Fig 6-8 & 6-9 do not match the figures

E.g the third bullet point mentions a slow down at 17:50 UTC but the graphs are between 08:54 and 09:03

Note from the Author or Editor:
True, nice catch, thanks! Will be fix in the next errata. Since the graphs were reproduced many times, the whole point about side effect can be ignored (side effect didn't happen in the current graph) (:

Ivo  May 27, 2023 
Page 245
numbered list 2

> Otherwise, in theory, it is Θ(1).
Is this mean to cut out []byte without creating [][]byte ?

Note from the Author or Editor:
Correct, the fact we have an "allocation overhead" can be tied to implementation detail. Algorithmically one could say it's Θ(1).

Will clarify in the next book errata, thanks!

Anonymous  Nov 01, 2023 
Page 256
2nd last paragraph

> Optimizations and benchmarking routines, as it stands today, involve a lot of manual work from developers. We need to run experiments with different algorithms and code, while caring about reproducing production and performance nondeterminism. Due to the manual nature, this is prone to human error.

Does this "production" mean "production environment" or "the result from the system"?

Note from the Author or Editor:
Changing "production" here to "production environment" would be a great clarification. Thanks!

Yoshi Yamaguchi  May 09, 2023 
Page 261
3rd paragraph

> if we don’t have the data in the registers, the CPU has to fetch it from L-caches, which might take one nanosecond. If L-caches contain data the CPU needs, our single statement might take 50 ns.

This sentens says 'cached data is slower than non-cached data'. but isn't this the opposite ?

Note from the Author or Editor:
You are right, there is a typo, it should be " if we don't have the data in the registers, the CPU has to fetch it from L-caches, which might take one nanosecond. If L-caches does not contain that data either, our single statement might take 50 ns."

Thanks!

Anonymous  Oct 11, 2023 
Page 279
Bullet point 3

> This means it will execute our benchmark once with b.N that equals 1 m only to assess a single iteration duration.

The word "m" in this sentence is not clear. I assume this "m" means "minute" in this context but I need the clarification.

Note from the Author or Editor:
Actually it should be "one" instead of "1 m", as I meant one iteration. Thanks!

Yoshi Yamaguchi  Feb 23, 2023 
Page 294
2nd last paragraph

> e.g., in the description of the pull report

I think this is typo of "the pull request".

Note from the Author or Editor:
Yes, thanks!

Yoshi Yamaguchi  Feb 24, 2023 
Page 296
2nd paragraph

> If the initialization takes too much time and impacts your feedback loop, you can add the code that will cache test the input on the filesystem.

What does "the code" in the latter half do? Does it "cache" and "test" the input on the filesystem? I couldn't parse the sentence.

Note from the Author or Editor:
Nice finding, it's a typo. Should be "...add the code that will cache the test input...". Thanks!

Yoshi Yamaguchi  May 09, 2023 
Page 314
Last line before } in Example 8-20 snippet.

The code line have:

testutil.Ok(t, `e2einteractive.RunUntilEndpointHit()`)

However, the quotes are wrong here, it should be without quotes:

testutil.Ok(t, e2einteractive.RunUntilEndpointHit())

Bartłomiej Płotka  Nov 21, 2022 
Page 326
Step 5.

Step 5. contains “Then I benchmark again ( see step 5)…
I believe it should reference “step 4” instead

Note from the Author or Editor:
Yes, thanks!

Ivo  Jun 01, 2023 
Page 336
numbered list 4

> Then we take a snapshot of this situation in the form of our fd.inuse profile.

n the explanation, it's referred to "fd.inuse," but in the program code, it's written as "fd.pprof."

Note from the Author or Editor:
Nice catch -- this is actually correct as fd.inuse is name of the profile and fd.pprof is the file name used. I clarified in errata, thanks!

Anonymous  Nov 01, 2023 
Page 374
4th paragraph

> even use the embedded `tool pprof` like a viewer to analyze them.

I assume the sentence should be "even use the embedded `go tool pprof` like a viewer to analyze them. I think "go" is dropped from the line.

Note from the Author or Editor:
Correct, thanks!

Yoshi Yamaguchi  Mar 07, 2023 
Page 383
Optimizing Latency first parapgraph

> … to achieve a throughput of at least 10 * N nanoseconds. The baseline results give us 50 * N nanoseconds.

From my understanding throughput should be measured in units per time. Per Example this would be “ at least one line per 10 nanoseconds”. The baseline results give us 1/5 line per nanosecond”.
Since the section is about latency I believe it would be clearer to use “ a latency of at most 10 * N nanoseconds”

Note from the Author or Editor:
Yes, good point, thanks!

Ivo  Jun 09, 2023 
Page 399
enumerated bullet point 3

> e.g., we read ...\n12 and 34/n... in two different chunks.

"/n" after 34 should be "\n" (line break character)

Note from the Author or Editor:
Correct, should be:

e.g., we read ...`\n12` and `34\n`... in two different chunks

Yoshi Yamaguchi  Apr 09, 2023 
Page 399
numbered list 6

> we might read less than 10KB of bytes, so we need to process only n of them. We process all lines found in our 10 KB buffer in each loop iteration.

It's written as "10kb," but it is actually "8kb"?

Note from the Author or Editor:
nice catch thanks!

Anonymous  Nov 02, 2023 
Page 406
enumerated bullet point 2

> Beware of common mistakes. The for _, line := range <-workCh would sometimes compile as well, and it looks logical, but it’s wrong. It will wait for the first message from the workCh channel and iterate over single bytes from the received byte slice. Instead, we want to iterate over messages.

What does the second sentence of this bullet point actually mean? My understanding is that the snippet causes a compile error and nothing happens. So I could not figure out what the second sentence is trying to say.

Note from the Author or Editor:
Great point!

I plan to fix it by replacing those sentences to

"Beware of a common mistake! In this line, we want to iterate over incoming byte slice messages until the channel is closed. Since it's easy to forget the syntax, it's easy to construct `for _, line := range <-workCh`, by accident. Despite looking logical, it will wait for the first message from the `workCh` channel and iterate over each byte from the received slice. Since it's a channel with byte slice messages, such code may compile and surprise us."

WDYT? Thanks!

Yoshi Yamaguchi  May 09, 2023 
Page 407
3rd paragraph

> We still don’t see the actual work, like parsing integers, since this work has outnumbered the overhead.

I think the last part of this sentence is the opposite. I suspect that this sentence tries to mean "We still don't see the actual work, like parsing integers, since the overhead outnumbered this work." The following paragraph also says:

> As a result, parsing and additions are faster than the communication overhead.

Note from the Author or Editor:
Nice catch, agree. Fixed it to:

```
We still don't see the actual work, like parsing integers, since the overhead have hidden it. This time the overhead is caused by three elements:

`runtime.schedule`:: The runtime code responsible for scheduling goroutines.
`runtime.chansend`:: In our case, waiting on the lock to send to our single channel.
`runtime.chanrecv`:: The same as `chansend` but waiting on a read from the receive channel.

Essentially, coordination and distribution of the work take more CPU resources than the work itself.
```

Thanks!

Yoshi Yamaguchi  May 09, 2023