Archive for December 15th, 2016

How do you find out the number of CPU cores available in your Linux system? Here are a number of way, pick the one which works for you –

1. nproc command –

[daniel@kauai tmp]$ nproc

2. /proc/cpuinfo

[daniel@kauai tmp]$ grep proc /proc/cpuinfo 
processor	: 0
processor	: 1

3. top – run top command and press ‘1’ (number 1), you will see the list of cores at the top, right below tasks.

Cpu0 : 0.7%us, 0.3%sy, 0.0%ni, 99.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu1 : 2.7%us, 1.0%sy, 0.0%ni, 96.3%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

4. lscpu – display information about the CPU architecture. Count Sockets times Core(s) per socket, in this case 2 x 1=2 –

[daniel@kauai tmp]$ lscpu 
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                2
On-line CPU(s) list:   0,1
Thread(s) per core:    1
Core(s) per socket:    2
Socket(s):             1
NUMA node(s):          1
Vendor ID:             AuthenticAMD
CPU family:            16
Model:                 6
Model name:            AMD Athlon(tm) II X2 250 Processor
Stepping:              3
CPU MHz:               3000.000
BogoMIPS:              6027.19
Virtualization:        AMD-V
L1d cache:             64K
L1i cache:             64K
L2 cache:              1024K
NUMA node0 CPU(s):     0,1

5. Kernel threads – pick one of the kernel house keeping threads, such as “migration” or “watchdog” and see on how many cores it is running –

[daniel@kauai tmp]$ ps aux |grep '[m]igration'
root         3  0.0  0.0      0     0 ?        S    Dec09   0:02 [migration/0]
root         7  0.0  0.0      0     0 ?        S    Dec09   0:02 [migration/1]

[daniel@kauai tmp]$ ps aux |grep '[w]atchdog'
root         6  0.0  0.0      0     0 ?        S    Dec09   0:00 [watchdog/0]
root        10  0.0  0.0      0     0 ?        S    Dec09   0:00 [watchdog/1]

The Shell has environment variables which determine its behavior. Exported environment variables are also popular ways of making an application change its behavior. These environment variables can be loaded or ‘sourced’ using the source builtin command or ‘.’ notation. In this post, I will share a particular problem I encountered while sourcing environment variables I saved in a .envrc file.

Problem – sourcing .envrc was not loading the right environment variables, including ‘. envrc’. Renaming .envrc to any other file works though.

[daniel@kauai tmp]$ cat .envrc 
NAME='Jhon Doe'
[daniel@kauai tmp]$ source .envrc 
[daniel@kauai tmp]$ echo $NAME
Alice Bob

As you can see, the variable NAME was set to ‘Jhon Doe’ and yet after sourcing .envrc, NAME is showing ‘Alice Bob’! Renaming the file seems to resolve the issue –

[daniel@kauai tmp]$ source .envrcs 
[daniel@kauai tmp]$ echo $NAME
Jhon Doe

Troubleshooting using strace – I followed the tips on ‘is-it-possible-to-strace-the-builtin-commands-to-bash’ to strace ‘source’. Stracing shell builtins is not straight forward. After looking at the output, I found out that the shell builtin source was actually reading the .envrc from a different directory, not my current working directory! The directory it was sourcing from was one of the directories in $PATH environment variables.

Read the man pages – Looking at the man page for bash, under the section for source command –

source filename [arguments]
Read and execute commands from filename in the current shell environment and return the exit status of the last command executed from filename. If filename does not contain a slash, file names in PATH are used to find the directory containing filename. The file searched for in PATH need not be executable. When bash is not in posix mode, the current directory is searched if no file is found in PATH. If the sourcepath option to the shopt builtin command is turned off, the PATH is not searched. If any arguments are supplied, they become the positional parameters when filename is executed. Otherwise the positional parameters are unchanged. The return status is the status of the last command exited within the script (0 if no commands are executed), and false if filename is not found or cannot be read.

Apparently this is an expected behavior. If I hadn’t a .envrc file in one of the $PATH directories, this would have been fine. In this case, there are several solutions –

1. Remove .envrc from $PATH directories [not the best option ]
2. Rename .envrc to a different file [ not ideal either ]
3. When sourcing the file, use absolute path [ good practice ]

[daniel@kauai tmp]$ echo $NAME
Alice Bob
[daniel@kauai tmp]$ pwd
[daniel@kauai tmp]$ source /tmp/.envrc 
[daniel@kauai tmp]$ echo $NAME
Jhon Doe

4. When sourcing the file, add slash(‘/’), for instance – source ./.envrc [ good practice ]
5. Disable sourcepath shell option [ not bad idea ]

[daniel@kauai tmp]$ shopt sourcepath
sourcepath     	on
[daniel@kauai tmp]$ shopt -u sourcepath
[daniel@kauai tmp]$ source .envrc 
[daniel@kauai tmp]$ echo $NAME
Jhon Doe

Bottom line – Make sure you understand how environment variables sourcing or loading works in bash and you follow good practices, so that you won’t wast precious hours trying to figure out why your script is behaving strangely.