I quote "This function is called with the world stopped, at the beginning of a garbage collection."
March 5, 2018Golang Advanced Compiler Directives
About 3 minutes of reading.
Last week, I took the time searching for patterns inside the main packages. Besides a bunch of
moments, I’ve realized that some neat tricks can be used to achieve some goals otherwise
achievable by applying different techniques.
For instance, let’s say you have a pool or a cache. How do you call your cleanup function?
Decisions regarding where to place that call can be made by testing and benchmarking. But what if there is another neat way to do so : just before the garbage collection runs, you can mount yourself a function and receive a call on it.
A compiler directive is a meta information that instructs the compiler on how to behave in certain conditions.
In our case, we’re using the
sync.pool method of
cleaning up the pool:
```go //go:linkname runtime_registerPoolCleanup sync.runtime_registerPoolCleanup func runtime_registerPoolCleanup(cleanup func()) ```
Here’s what we need to do :
- in our package, create a file named
empty.s. As the name says, it’s empty.
- in the file where we’re going to declare the linkname directive, we have to import “unsafe”
import _ "unsafe".
use the directive :
//go:linkname registerCacheCleanupFn sync.runtime_registerPoolCleanup func registerCacheCleanupFn(f func())
in the same file, declare the
init()function and call
registerCacheCleanupFnwith our cleaning function implementation as parameter.
Advantages of using this technique are obvious. However, we have to keep in mind that our cleaning up implementation should NOT allocate and should NOT call any runtime functions - unless you think you are Mario (the plumber) and can deal with any kind of leak.
What else can we use?
If we to avoid importing “strings” just like parse.go inside “net” package does, but still be able to call IndexByte, we need the following declaration :
//go:linkname ByteIndex strings.IndexByte func ByteIndex(s string, c byte) int
You might find these below useful as well.
//go:linkname BytesEqual bytes.Equal func BytesEqual(x, y byte) bool
//go:linkname IndexByte bytes.IndexByte func IndexByte(s byte, c byte) int
//go:linkname Compare bytes.Compare func Compare(a, b byte) int
//go:linkname TimeSleep time.Sleep func TimeSleep(ns int64)
//go:linkname StartTimer time.startTimer func StartTimer(t *timer)
//go:linkname StopTimer time.stopTimer func StopTimer(t *timer) bool
//go:linkname PollNano internal/poll.runtimeNano func PollNano() int64
//go:linkname TimeNano time.runtimeNano func TimeNano() int64
//go:linkname Now time.now func Now() (sec int64, nsec int32, mono int64)
A Side Note
By the way : I’ve noticed that strings.Index is sometimes unnecessary called when the second parameter
is just a byte (e.g.
strings.Index(url, "?") in server.go).
I know it is a micro optimization, but hey, let’s use the right tool for the right job, shall we?
Same observation goes for bytes.IndexByte too.
Another observation regards strings.TrimPrefix and strings.TrimSuffix - I’ve notice that sometimes developers checks if string has prefix or suffix before calling them, which is unnecessary because the check is done inside those functions. Perhaps it would be better to change the signatures of those functions like this :
func TrimPrefix(s, prefix string) (bool, string) // returning true if string had that prefix and the trimmed string
Would be really useful for testing to have a directive that instructs the compiler to include or exclude portions of code, thus we can avoid including testing portions in the production.
Of Mice (Unsafe) and Men (Reflect)
March 10, 2018Golang Advanced Reflect Unsafe
About 12 minutes of reading.
About routing and searching using radix trees.
February 27, 2018Golang Radix Tree Router Search
About 10 minutes of reading.
A deep dive into it net/http package.
February 24, 2018Golang Net Http Analysis
About 5 minutes of reading.