Sunday, September 6, 2020

Building a Binary with arguments and options - flags package in golang


In this post, I will provide information about building a go program with arguments and options.


Typically, an executable can contain
  • Arguments: Go expects these to be provided after all the options.
  • options (specified with - & provided with an option value). Example: "-srcDir /tmp". Go calls these as "flags".
  • flags: True if specified, else false. Example: "-e" to enable/disable. Go doesn't support this type of flags !!!

Here is a sample binary I built to test go flags. Sample outputs running the above binary:

  • How to get help text?

 


So, we get help text free if we use flags package !! 

  • Run the program without any inputs:


  • Run the program without any additional arguments
                
  • Run the program with an additional argument
      

Some drawbacks I see with go flags package:

  • As we saw earlier, go flags package doesn't provide a way for us to specify mandatory options. We need to either write additional code (like I provided above) or use custom packages such as go-flags
  • go doesn't support true/false kind of flags

TBD:
  • flagSet (building subcommands)


References:

https://golang.org/pkg/flag/
https://blog.rapid7.com/2016/08/04/build-a-simple-cli-tool-with-golang/
https://gobyexample.com/command-line-flags
https://stackoverflow.com/questions/31786215/can-command-line-flags-in-go-be-set-to-mandatory/31786480#:~:text=The%20flag%20package%20does%20not,halt%20with%20an%20error%20message






Sunday, August 23, 2020

Volatile Variables in Golang

   

In the past, I have used lockless code when there is a single reader and single writer and the reader can accept stale information to some extent (for example, this sample code on my github) .



However, there is a problem in this code. If the two go routines run on different cpu cores, then the reader go routines may never get changes from writer go routine? So, the solution I typically employed in languages such as C/C++ is to use volatile type for flag. However, go doesn't seem to support volatile variables as per these discussions: google groups discussion, stackoverflow discussion!! 

So, the solution for the above situation is to use an atomic variable. To find the correct way of writing the above code, please check here.


Skipping Go Race detector for some packages

  

In my previous post, I covered the basics of Go Race detector. In most Golang, projects, we would have multiple projects. 

For some reason, if we want to skip race detector for some packages, we can use this option as the first line of the package & an empty second line:

// +build !race


I ran the sample code on my github with the above option to get this:
Babus-MacBook-Pro:Race_Tests_inGolang babuneelam$ go build -race
package racetest: build constraints exclude all Go files in /Users/babuneelam/Projects/GoProjects/Race_Tests_inGolang
Babus-MacBook-Pro:Race_Tests_inGolang babuneelam
I have only a single package in this, so this error. If I were to have multiple packages in this repository, it would have build those.

Exploring Go Race Detector

   

I got to know about Golang Race Detector from a colleague & wanted to give this a try. Here is the sample code on my github  I tested (also, same code on Go playground for quicker testing).

We can use race detector in multiple ways:

1) Using go run -race with the specific go file:
Babus-MacBook-Pro:Race_Tests_inGolang babuneelam$ go run -race main.go
flag:  true
==================
WARNING: DATA RACE
Write at 0x0000012742a1 by goroutine 7:
  main.writer()
      /Users/babuneelam/Projects/GoProjects/Race_Tests_inGolang/main.go:12 +0x55

Previous read at 0x0000012742a1 by main goroutine:
  main.reader()
      /Users/babuneelam/Projects/GoProjects/Race_Tests_inGolang/main.go:19 +0x3e
  main.main()
      /Users/babuneelam/Projects/GoProjects/Race_Tests_inGolang/main.go:27 +0x5e

Goroutine 7 (running) created at:
  main.main()
      /Users/babuneelam/Projects/GoProjects/Race_Tests_inGolang/main.go:26 +0x59
==================
flag:  true
^Csignal: interrupt
Babus-MacBook-Pro:Race_Tests_inGolang babuneelam

 

2) Build the go program with "-race" flag:

Babus-MacBook-Pro:Race_Tests_inGolang babuneelam$ go build -race
Babus-MacBook-Pro:Race_Tests_inGolang babuneelam

Then, run the program:

Babus-MacBook-Pro:Race_Tests_inGolang babuneelam$ ./racetest 
flag:  true
==================
WARNING: DATA RACE
Write at 0x0000012742a1 by goroutine 7:
  main.writer()
      /Users/babuneelam/Projects/GoProjects/Race_Tests_inGolang/main.go:12 +0x55

Previous read at 0x0000012742a1 by main goroutine:
  main.reader()
      /Users/babuneelam/Projects/GoProjects/Race_Tests_inGolang/main.go:19 +0x3e
  main.main()
      /Users/babuneelam/Projects/GoProjects/Race_Tests_inGolang/main.go:27 +0x5e

Goroutine 7 (running) created at:
  main.main()
      /Users/babuneelam/Projects/GoProjects/Race_Tests_inGolang/main.go:26 +0x59
==================
flag:  true
flag:  true
^C
Babus-MacBook-Pro:Race_Tests_inGolang babuneelam

 

3)  go test -race mypkg - TBD

4)  go install -race mypkg - TBD


As we can see the go race detector displayed us two pieces needed:
  1. A race warning  
  2. The two code locations that are causing the race
So, it's quite useful. To find the correct way of writing the above code, please check here.

However, this is not a static analysis tool. So, we need to run the program to detect the races. And only those races that happen during execution are detected. If we use race as part of test cases, then race detector is only as effective as your test coverage !!

In terms of performance, Golang Race Detector says this:

The cost of race detection varies by program, but for a typical program, memory usage may increase by 5-10x and execution time by 2-20x.

The race detector currently allocates an extra 8 bytes per defer and recover statement. Those extra allocations are not recovered until the goroutine exits. This means that if you have a long-running goroutine that is periodically issuing defer and recover calls, the program memory usage may grow without bound. These memory allocations will not show up in the output of runtime.ReadMemStats or runtime/pprof.

So, this is definitely not for production environments.

Saturday, August 22, 2020

List of Standard Packages and Sub-repositories in Golang

 
I have been working in Golang for a while now. However, I only explored some packages like fmt, context, sync, time etc. But, I always wanted to know the entire list of standard packages available in Golang. 

Today, I found the list here: Go Standard Packages

Also, check sub-repositories here: Go sub-repositories

In future, I also would like to research a list of useful third party packages as well. 

Saturday, August 8, 2020

Online IDE for Golang: Go Playground


Golang has an online IDE here: Go Playground. Here we can experiment sample programs and share code snippets with others. As per the discussion in the google groups here, the shared urls seem to be retained forever - at least for now.

The online IDE doesn't autofill methods, imports etc like IDEs like IntelliJ, Eclipse do. That would have been even nicer.

More details about this playground:

Also, "About" page on the online IDE page has a bit more details such as limitations etc.


TBD:
  • How do we run a go program in the online IDE with input arguments?

Sunday, June 28, 2020

IntelliJ Keymap


I started using IntelliJ recently. Here is the key map that can be useful:




References:
https://resources.jetbrains.com/storage/products/intellij-idea/docs/IntelliJIDEA_ReferenceCard.pdf
UA-48797665-1