Talk about how to get Goroutine ID

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

At the beginning of last year, I wrote an article about how to get Goroutine ID: How to get Goroutine ID? At that time, some methods of acquiring Goid were investigated. There are three basic methods:

    1. Parse out ID with stack information
    2. Get runtime·getg The call result of a method by assembly
    3. Direct modification of the runtime code, export a Goid () method that can be called externally

There are some problems in every way, #1比较慢, #2因为是hack的方式 (go team does not want to expose the information of Go ID), for different go version need special hack means, #3需要定制Go运行时, not universal. At the time, Petermattis/goid provided #2 method, but only in go 1.3, so you can only select # # to get the go ID.

Over the past year, Petermattis has updated his code to add support for Go 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, as well as the # # method, as an alternative when the # # method doesn't work. So we can use stable's method of getting go ID in all the current versions.

You may encounter scenarios where you need to use Go ID, for example, when multiple goroutine are running for a long time, we track the execution of the task through the log, and the Go ID can be used to roughly track the state of the program's concurrency execution.

12345678910111213141516171819202122
 Package mainimport ("Log""Time""github.com/petermattis/goid")   Func Main () { for i: = 0; i < ; i++ {gofunc() { J: = 0; J < 1000000; J + + {log. Printf ("[#%d]%d", goid. Get (), j) time. Sleep(10e9)}} ()}select {}}

According to the document hacking in the Go Code, a method is implemented in the Go runtime to getg() get the current goroutine:

getg()Alone returns the currentg

Of course, this method is an internal method, not a exported, cannot be called externally, and the data structure returned is not exported. If there is a way to expose this method, the problem is solved.

Petermattis/goid Imitation runtime.getg exposes a getg method

Https://github.com/petermattis/goid/blob/master/goid_go1.5plus.s
12345678910
+build amd64 amd64p32//+build go1. 5"textflag.h"//Func GETG () uintptrtext GETG (SB),nosplit
        ,$8movqbxmovqbxret+0(FP )RET

The above code actually returns the pointer (TLS) of the structure of the current goroutine.

Reference: Golang Internals and Chinese translation Go Language Insider
TLS is actually the abbreviation for thread local storage (thread locally Storage). This technique is useful in many programming languages (refer to here). Simply put, it provides one such variable for each thread, with different variables used to point to different areas of memory.

In the Go language, TLS stores a pointer to a G struct. The structure that the pointer points to includes the internal details of the Go routine (which is discussed in more detail later). Therefore, when you access the variable in a different routine, you actually access the struct to which the corresponding variable of the routine is pointing. The linker knows where the variable is located, and the previous instruction moves to the CX register, which is the variable. For AMD64,TLS is implemented with FS registers, where the commands we see earlier can actually be translated into Movq FS, CX.

Different go versions of the data structure may be different, so petermattis/goid for 1.5, 1.6, 1.9 has a changed version of the different data structure, because we just need to get Goroutine ID, so just implement:

1234
func Int64 {GG: = (*g) (unsafe. Pointer (GETG ()))return gg.goid}

I compare the performance of the two implementations of # # and # #, and the gap is very large:

123456789101112131415161718192021222324
 Package pkgimport ("Runtime""testing""github.com/petermattis/goid") func Benchmarkasm (b *testing. B) {B.reportallocs () for i: = 0; i < B.N; i++ {goid. Get ()}}func benchmarkslow (b *testing. B) {B.reportallocs ()var[+]byteb.resettimer () for i: = 0 false)]}}

Performance Comparison results:

12
BenchmarkASM-4    300000000         3.70 ns/op       0 b/op       0 allocs/opbenchmarkslow-4     300000      4071 ns/op       1 b/op       1 allocs/op

1000 times the gap.

petermattis/goidThis hack approach exposes more details of the runtime, such as the ability to expand, get m information about which is currently running, and even get the current thread:

 1234567891011121314151617181920212223 
 type  m struct  {G0 * Gmorebuf gobufdivmod uint32  procid uint64  gsignal *gsi Gmask sigsettls [6 ]uintptr  mstartfn func  () Curg *gcaughtsig uintptr  P uintptr  N EXTP uintptr  ID int32 }func Getm () int32  {gg: = (*g) (unsafe. Pointer (GETG ())) M: = (*m) (unsafe. Pointer (GG.M)) return  m.id} 

Sigset is not the same size on different platforms, you can refer to the definitions of each platform in Os_*.go. The above is the ID of the m , and the structure of the more complete m defines the sea as including thread .

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.