2015年5月29日 星期五

在 Linux 上使用 RAM Disk 提高資料讀寫速度



http://blogger.gtwang.org/2013/01/linux-ram-disk.html

在 Linux 上使用 RAM Disk 提高資料讀寫速度

RAM Disk 就是將動態記憶體(Dynamic Random Access Memory,DRAM)經由軟體模擬的方式,拿來當作一般硬碟使用,優點就是讀寫速度很快、壽命也比一般硬碟長,但是缺點是斷電時資料就會消失。由於記憶體的存取速度比傳統硬碟、固態硬碟(SSD)或磁碟陣列的速度更快,因此將記憶體模擬為硬碟後,可以利用其優越的讀寫能力,提升系統執行效率。

RAM Disk 不像傳統硬碟採用馬達與磁片等機械裝置,而是靠電子訊號傳輸,因此在分類上也算是固態硬碟(Solid State Disk),但其讀寫效能卻是一般市售 SSD 無法相比的!相較市面上高速 SSD 可達 500MB/s 的讀寫速度,或者高達 1000MB/s 速度的 PCI Express SSD 磁碟陣列產品,RAM Disk 讀寫速度是前述產品的數倍有餘,而且更為便宜。

RAM Disk 效能會受到軟體、記憶體時脈、晶片組的記憶體通道數而有所不同。扣除軟體差異,記憶體時脈越高則效能越好,而四通道平台又比雙通道來得快一些,但無論如何,記憶體的存取效率還是優於其他的儲存裝置。

在 Linux 中若要使用 RAM Disk,只需要使用 mount 這個指令就可以了,非常簡單!

首先在 /tmp 中建立一個資料夾:
mkdir /tmp/ramdisk
chmod 777 /tmp/ramdisk


接著再使用 mount 指令將 4G 的記憶體掛上去:
mount -t tmpfs -o size=4G tmpfs /tmp/ramdisk/

這裡要使用 -t 參數指定檔案系統類型為 tmpfs,並且使用 -o 參數指定 RAM Disk 大小為 4G。


建立好 RAM Disk 之後,用 df 檢查一下:
df -h

輸出為:
檔案系統        容量  已用  可用 已用% 掛載點
/dev/sda1       116G  8.7G  101G    8% /
udev             16G  4.0K   16G    1% /dev
tmpfs           6.3G  332K  6.3G    1% /run
none            5.0M     0  5.0M    0% /run/lock
none             16G     0   16G    0% /run/shm
tmpfs           4.0G     0  4.0G    0% /tmp/ramdisk

最後一行就是我們剛剛建立的 RAM Disk,容量是 4G,現在就可以把 /tmp/ramdisk 當做一般的硬碟使用了。

接著我們來測試寫入 2G 的資料到 RAM Disk 中,看看效率如何:
dd count=2k bs=1M if=/dev/zero of=/tmp/ramdisk/test2g.img
輸出為
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 3.59279 s, 598 MB/s

接著我們將相同的資料寫入一般的硬碟,跟 RAM Disk 比較看看:
dd count=2k bs=1M if=/dev/zero of=/tmp/test2g.img
輸出為
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 39.76 s, 54.0 MB/s

在寫入速度上確實有很大的差異,接著再來看看讀取速度,從 RAM Disk 中讀取 2G 的資料:
dd count=2k bs=1M if=/tmp/ramdisk/test2g.img of=/dev/null
輸出為
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 1.93749 s, 1.1 GB/s

從一般硬碟中讀取 2G 的資料:
dd count=2k bs=1M if=/tmp/test2g.img of=/dev/null
輸出為
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 2.42428 s, 886 MB/s

這裡有一個奇怪的現象,從一般硬碟中讀取資料的速度很快,這是因為在 Linux 中會使用多餘的記憶體作為檔案的 Cache,所以才會有這麼快的讀取速度,如果想知道實際的硬碟讀取速度,可以強迫系統將 Cache 釋放後,再來讀取:
sudo echo 3 > /proc/sys/vm/drop_caches
dd count=2k bs=1M if=/tmp/test2g.img of=/dev/null

輸出為
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 35.7114 s, 60.1 MB/s

這樣看起來就比較像實際的狀況了。

事實上在前面的硬碟寫入時,也會有 buffer 的問題,Linux 在寫入資料到檔案時,有時候會先將資料放進 buffer 中,沒有馬上寫進硬碟,這樣會比較有效率。所以事實上硬碟的速度沒有那麼快,也就是因為 Linux 系統中有這樣的 buffer 機制,所以在關機或是重新開機時,都會需要把每個硬碟進行 umount,將資料寫入硬碟後才斷電,這也就是為什麼隨身碟或外接硬碟插在 Linux 系統下,要拔起來時一定要正常 umount 完才能拔,否則運氣不好的話,就會把一些資料遺漏在記憶體中,導致資料的損毀。

我想我們在這裡只是做一個大概的測試,不用很精準,如果想很精準的測試出硬碟的寫入速度,可以在 dd 指令後加上 sync,強迫資料寫入硬碟,再計算兩者的的時間,不過不管怎麼做都還是會有誤差,因為系統中一定有其他的 process 在跑,若其他的 process 也有讀寫硬碟的動作,就會影響測試的數據,所以這裡我想就大約看看就好了。

我們把上面測試的數據畫成長條圖來看看,下面這張圖就是 RAM Disk 與硬碟的差異:




很明顯的可以看出 RAM Disk 與一般硬碟的寫入速度相差非常多。

這裡的數據是我用一臺舊電腦測試的,所以效率看起來不高,接著用一臺比較新的電腦測試看看:




這台電腦比較新,硬碟是由四顆實體硬碟串起來做 RAID 5,所以硬碟效能好很多,而記憶體的存取速度也比電腦快,所以整體效能都比舊機器好。在這裡也可以看出來,不管在新舊的電腦上,RAM Disk 與一般硬碟始終存在很大的差異。

2015年5月19日 星期二

Linux 下 什麼是 Free Cache Buffer Memory

http://blogger.gtwang.org/2013/07/linux-cache-memory-linux.html

Linux 的記憶體快取(Cache Memory)功能 - Linux 系統把記憶體用光了?

這裡 Linux 記憶體中的記憶體快取(Cache Memory)是什麼,並討論相關的一些指令用法。

在 Linux 中系統會將暫時沒有用到的記憶體借來當作磁碟的快取(cache),而在用 top 指令看系統的 free 的記憶體時,感覺記憶體好像所剩無幾,有些人就會以為 Linux 系統把記憶體吃光光了,然後就推測這樣系統會用到 swap 記憶體,效能也會跟著下降,但其實不是這樣的,而且真正的情況剛好相反。

實際上 Linux 系統拿沒有用到的記憶體當作硬碟的快取,可以會讓整個系統的效能提昇很多,而且沒有任何副作用(除了讓一些不了解的人很緊張之外),它只是「暫時」把沒有用到的記憶體借來用一下而已,當有程式需要記憶體時,系統就會馬上把記憶體拿回來給需要記憶體的程式使用,完全沒有霸佔記憶體的問題。

有些人也會擔心這樣的機制會不會讓系統使用到 swap 記憶體?事實上這也不用擔心,快取只會用到暫時沒有使用 RAM,並不會使用到 swap 來作為快取(使用 swap 也沒什麼意義,因為 swap 就是在磁碟上,不會比較快)。

至於有時候整個系統中沒有在執行什麼程式,而用 top 與 free 指令查看記憶體使用狀況時,會顯示很大一部分的記憶體是 used 的狀態,不懂的人就會感覺很奇怪,這其實是對於他的意義有些誤解,我們用下面這個表來解釋:
記憶體狀態你的認知Linux 系統的認知
正在被應用程式使用UsedUsed
可以被應用程式使用,但被暫時借去做別的用途FreeUsed
沒有被使用FreeFree
會出問題就在於記憶體暫時借去做別的用途時(像硬碟快取),Linux 系統會顯示 used,但是大部分人應該會認為這部份的記憶體應該顯示為 free,就是因為這個落差,導致很多人誤以為系統的記憶體被吃光,換句話說,那些被標示為 used 的記憶體其實包含被拿去作為快取的部份,而這些部份其實在程式需要時是可以馬上拿回來的,所以可以被一般應用程式使用的記憶體會比你想像的要多一些。

既然看一般的 top 輸出的 free 記憶體不太準,那到底要如何知道我們實際上真正可以用的記憶體有多少呢?其實可以使用 free 指令來看,只是在看他的輸出的時候,要知道看哪一個欄位:
free -m
輸出為:
             total       used       free     shared    buffers     cached
Mem:          3953       3154        799          0        135        990
-/+ buffers/cache:       2029       1924
Swap:         3813          0       3813
若要看實際上應用程式可用的記憶體就看 -/+ buffers/cache 這一行的 free 這一欄有多少就是了,我們這裡使用 -m 參數,所以這裡的單位都是 MB,以這個例子來說就是還有 1924 MB 可以使用,而如果你只是單純看上面的 Mem 那一行,你可能會以為系統只剩下 799 MB 的記憶體了。

除了使用 free 指令之外,也可以使用比較直覺的 htop 工具,它類似 top 指令,但是有更人性化的輸出,下面這個是他的使用畫面:

htop 畫面

其中 Mem 的部份就會顯示目前的記憶體使用狀況,而它會以不同顏色表示不同的記憶體的使用狀況,像快取的話就會使用黃色表示,這樣可以讓管理者更容易看出整體記憶體的狀況。

網路上有很多清除快取記憶體的教學,這些動作其實對於整個系統效能是沒有幫助的,甚至你把硬碟快取強制清除之後,因為沒有快取的輔助,導致有些資料還要重新從硬碟讀取,反而讓整體效能更差也不一定,而且重點是不管你有沒有去手動釋放快取記憶體,只要你的程式需要記憶體時,都可以馬上使用這些記憶體空間,所以跟本不需要多花這些力氣。

以下是手動清除快取記憶體的方式,這裡只是純粹的討論技術,這個部份通常一般人是沒有什麼機會需要用到的,除非你有一些很特殊的需求,而且在做這些動作之前,你應該要很清楚自己在做什麼與需要什麼。

要釋放 Linux 的記憶體快取,可以透過更改 /proc/sys/vm/drop_caches 這個檔案的內容來達到,當這個檔案內容被設為 1 時,是表示要求 Linux 釋放沒在使用的一般性快取(pagecache),而設為 2 時,則代表要求釋放 dentry 與 inode 所使用到的快取,若設為 3 則是釋放所有的快取(也就是包含 1 與 2 的狀況)。

在設定時,也可以加上 sync 指令,讓一些沒有寫入硬碟的資料先寫入之後,才將快取釋放,另外這個指令會需要 root 權限,所以整個完整的指令就會像這樣:
sudo sh -c "sync; echo 3 > /proc/sys/vm/drop_caches"
另外,如果不想使用 echo,也可以用 sysctl 指令的方式:
sudo sysctl vm.drop_caches=3
最後再強調一次,這個釋放快取的動作在大部分的狀況是沒有什麼好處的,所以如果你要使用,請先搞清楚這是在做什麼。

2015年5月18日 星期一

Installing Python 2.7.8 from source on Oracle Linux 6.5

http://bicofino.io/blog/2014/01/16/installing-python-2-dot-7-6-on-centos-6-dot-5/


Installing Python 2.7.8 on CentOS 6.5

 | COMMENTS
CentOS 6.5 still come with Python 2.6 and I need 2.7, below a simple tutorial how to achieve this with no pain and not messing with installed Python.

Update CentOS and install development tools

1
2
yum -y update
yum groupinstall -y 'development tools'
Also you need the packages below to enable SSL, bz2, zlib for Python and some utils:
1
yum install -y zlib-devel bzip2-devel openssl-devel xz-libs wget

Installing Python 2.7.8 from source

Download Python and extract it
1
2
3
wget http://www.python.org/ftp/python/2.7.8/Python-2.7.8.tar.xz
xz -d Python-2.7.8.tar.xz
tar -xvf Python-2.7.8.tar

Installation process

Since we already installed all the dependencies we are ready to go:
1
2
3
4
5
6
7
8
9
10
11
12
13
# Enter the directory:
cd Python-2.7.8

# Run the configure:
./configure --prefix=/usr/local

# compile and install it:
make
make altinstall

# Checking Python version:
[root@nicetry ~]# python2.7 -V
Python 2.7.8
If you need set PATH variable check the line below:
1
export PATH="/usr/local/bin:$PATH"

Installing pip and virtualenv

Now we have Python installed, but something is missing isn’t? Yes! We need pip and virtualenv.

Install setuptools

1
2
3
4
5
6
7
8
wget --no-check-certificate https://pypi.python.org/packages/source/s/setuptools/setuptools-1.4.2.tar.gz

# Extract the files:
tar -xvf setuptools-1.4.2.tar.gz
cd setuptools-1.4.2

# Install setuptools using the Python 2.7.8:
python2.7 setup.py install

Installing pip

1
curl https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py | python2.7 -

And finally virtualenv

1
pip2.7 install virtualenv
And that’s all, we have Python 2.7.8 installed on CentOS.

Linux vmstat auto logging

https://gist.github.com/mmichaelis/1187126

    Created 

    Embed URL

    HTTPS clone URL

    You can clone with HTTPS or SSH.
     Download Gist
    Monitoring System Load on Linux System with vmstat and generating graphs from it
    12345678910111213141516171819202122
    # exclude patterns (uncomment them if you want to use them):
    # *.[oa]
    # *~
    # idea:
    *.iml
    *.ipr
    *.iws
    .idea/
    # maven:
    target/
    overlays/
    *.releaseBackup
    # eclipse:
    .classpath
    .project
    .settings/
    # Logs:
    *.log
    *.err
    *.out
    # Git:
    *.orig

    VMLoad - The graphical vmstat-solution

    vmload got generated as a continuous observation of vmstat results. It tracks the results in CSV files and is able to generate graphs from these CSV files afterwards using gnuplot. You can either decide to generate the graphs directly after the run is completed or you can create a graph from given CSV files afterwards.

    Synopsis

    $ vmload.sh [-f <CSV-filename>] [-g] [-G] [-r <host>]
    

    Description

    Continuously runs vmstat as command with 1 second between each ping. Results are stored either into a temporary CSV file or a permanant one specified by the -f switch. Creating graphs with either -g or-G requires gnuplot to be installed.
    To exit the program press Ctrl+C which will (if requested) also automatically generate the graphs.
    • -h print short help
    • -f <name> specifies the output and/or input file where to write the CSV data to. If not specified the data will be written to a temporary file which is deleted afterwards.
    • -g will automatically generate graphs from the measured CSV data after the program got aborted with Ctrl+C. If the CSV file is non-permanent it will be deleted after graph generation.
    • -G will create the graphs from a given CSV file. It requires to set -f <name> and will fail otherwise.
    • -r <host> will execute the vmstat command on a remote host; host might be anything from just a remote hostname to remote hostname plus username.

    Examples

    $ vmload.sh
    
    Just runs continuous vmstat with 1 second delay. A temporary file will be written but deleted immediately after you stop the run with Ctrl+C
    $ vmload.sh -f vmload.csv
    
    Will run vmstat with 1 second delay and will write the results to a permanent file vmload.csv. Only one line of the two line vmstat-header is added. The first three columns in addition contain timestamp information.
    $ vmload.sh -g
    
    Runs the vmstat command and will generate graphs from the results afterwards. The temporary CSV file will be deleted.
    $ vmload.sh -f vmload.csv -g
    
    Just as before but the CSV data will be kept in a file named vmload.csv.
    $ vmload.sh -f vmload.csv -G
    
    Will not collect anymore data but will directly generate the graphs from the given CSV file of a previous run.
    $ vmload.sh -f vmload.csv -r someuser@somehost
    
    Will collect the data from the remote host. Only vmstat needs to be available on that host.
    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
    #!/bin/bash
    #
    # References
    # ~~~~~~~~~~
    #
    # Gnuplot
    # ~~~~~~~
    # http://www.yolinux.com/TUTORIALS/WebServerBenchmarking.html
    # http://www.groupsrv.com/computers/about179969.html
    #
     
    declare -r WINDOWS_GNUPLOT="${PROGRAMFILES}/gnuplot/binary/gnuplot.exe"
     
    [ -z "${AWK}" ] && AWK="$(which gawk)"
    [ -z "${AWK}" ] && AWK="$(which awk)"
    if [ -z "${AWK}" ]; then
    echo "[ERROR] Missing awk. Please place in path or set AWK environment property to point to executable." >&2
    exit 1
    fi
     
    [ -z "${GNUPLOT}" ] && GNUPLOT="$(which gnuplot)"
    [ -z "${GNUPLOT}" -a -f "${WINDOWS_GNUPLOT}" ] && GNUPLOT="${WINDOWS_GNUPLOT}"
     
    set -o nounset
    set -o errexit
     
    function printHelp() {
    cat <<HELP
    Usage: $0 [-h] [-f <filename>] [-g] [-G] [-r <host>]
    For a more descriptive help with examples read README.md.
    HELP
    }
     
    # Where to write the CSV data to; required if you want to create the graphs afterwards
    declare OUTPUT_FILE=""
    # If to create the graphs after the stats have been collected.
    declare CREATE_GRAPH=false
    # If to only create the graphs without generating new data. Requires a specified output-file (here: input-file)
    declare ONLY_CREATE_GRAPH=false
    # If the output file generated will only exist temporarily.
    declare IS_TEMP=true
    declare REMOTE_HOST=""
     
    while getopts ":hgGf:r:" Option; do
    case $Option in
    h )
    printHelp
    exit 0
    ;;
    f )
    OUTPUT_FILE="${OPTARG}"
    IS_TEMP=false
    ;;
    G )
    if [ -z "${GNUPLOT}" ]; then
    echo "[ERROR] Missing Gnuplot Tool. Either place gnuplot in path or set GNUPLOT to point to executable." >&2
    exit 1
    else
    ONLY_CREATE_GRAPH=true
    CREATE_GRAPH=true
    fi
    ;;
    g )
    if [ -z "${GNUPLOT}" ]; then
    echo "[WARNING] Missing Gnuplot Tool. No graphs will be generated. Either place gnuplot in path or set GNUPLOT to point to executable." >&2
    else
    CREATE_GRAPH=true
    fi
    ;;
    r )
    REMOTE_HOST="${OPTARG}"
    ;;
    * )
    echo "Unknown option." >&2
    echo ""
    printHelp
    exit 1
    ;;
    esac
    done
    shift $(($OPTIND - 1))
     
    if [ -z "${OUTPUT_FILE}" ]; then
    if ${ONLY_CREATE_GRAPH}; then
    echo "[ERROR] Requested to only create graph but missing input file. Use -f option to specify the file to plot." >&2
    exit 1
    fi
    # Generate a temporary file if none got specified
    OUTPUT_FILE="$(mktemp --suffix=.csv)"
    fi
     
    declare -r GNUPLOT_PAPER="\
    set size 1, 1; \
    set terminal png size 1024, 768; \
    set grid y"
     
    declare -r GNUPLOT_DATA="\
    set datafile separator ','; \
    set xdata time; \
    set timefmt '%s'; \
    set format x '%H:%M:%S'"
     
    declare -r GNUPLOT_LABELS="\
    set title TITLE font 'GNUPLOT_DEFAULT_GDFONT,14'; \
    set key outside center bottom horizontal box font 'GNUPLOT_DEFAULT_GDFONT,10'; \
    set xlabel 'Time' offset 0,-2; \
    set ylabel YLABEL offset 2,0; \
    set xtics axis autofreq rotate by -90 font 'GNUPLOT_DEFAULT_GDFONT,10'"
     
    declare -r GNUPLOT_PLOT_OPTIONS="smooth csplines with lines"
     
    declare -ri COL_TIMESTAMP=1
    declare -ri COL_DATE=2
    declare -ri COL_TOD=3
    declare -ri COL_PROCS_WAITING_NUMBER=4
    declare -ri COL_PROCS_BLOCK_NUMBER=5
    declare -ri COL_MEM_SWAP=6
    declare -ri COL_MEM_FREE=7
    declare -ri COL_MEM_BUFF=8
    declare -ri COL_MEM_CACHE=9
    declare -ri COL_SWAP_IN=10
    declare -ri COL_SWAP_OUT=11
    declare -ri COL_IO_BLOCKS_READ=12
    declare -ri COL_IO_BLOCKS_WRITE=13
    declare -ri COL_SYS_INTERRUPTS=14
    declare -ri COL_SYS_CONTEXT_SWITCHES=15
    declare -ri COL_CPU_USER_TIME=16
    declare -ri COL_CPU_SYSTEM_TIME=17
    declare -ri COL_CPU_IDLE_TIME=18
    declare -ri COL_CPU_WAIT_TIME=19
     
    declare -r COL_TIMESTAMP_LABEL="Timestamp"
    declare -r COL_DATE_LABEL="Date"
    declare -r COL_TOD_LABEL="Time of the Day"
    declare -r COL_PROCS_WAITING_NUMBER_LABEL="Procs waiting"
    declare -r COL_PROCS_BLOCK_NUMBER_LABEL="Procs blocked"
    declare -r COL_MEM_SWAP_LABEL="Virtual Memory"
    declare -r COL_MEM_FREE_LABEL="Idle Memory"
    declare -r COL_MEM_BUFF_LABEL="Memory for Buffers"
    declare -r COL_MEM_CACHE_LABEL="Memory for Cache"
    declare -r COL_SWAP_IN_LABEL="Swapped Memory in/s"
    declare -r COL_SWAP_OUT_LABEL="Swapped Memory out/s"
    declare -r COL_IO_BLOCKS_READ_LABEL="I/O: Received blocks/s"
    declare -r COL_IO_BLOCKS_WRITE_LABEL="I/O: Sent blocks/s"
    declare -r COL_SYS_INTERRUPTS_LABEL="Interrupts/s"
    declare -r COL_SYS_CONTEXT_SWITCHES_LABEL="Context Switches/s"
    declare -r COL_CPU_USER_TIME_LABEL="CPU User Time"
    declare -r COL_CPU_SYSTEM_TIME_LABEL="CPU System Time"
    declare -r COL_CPU_IDLE_TIME_LABEL="CPU Idle Time"
    declare -r COL_CPU_WAIT_TIME_LABEL="CPU Wait IO Time"
     
    function plotMemory() {
    local file="${1}"
     
    "${GNUPLOT}" << GNUPLOT_CMDS
    # The paper
    ${GNUPLOT_PAPER}
    set yrange [0:]
    # The data
    ${GNUPLOT_DATA}
    set output "${file}.memory.png"
    # Labels
    TITLE = "VMStat Memory"
    YLABEL = "Memory (MB)"
    ${GNUPLOT_LABELS}
    plot "${file}" using 1:${COL_MEM_SWAP} ${GNUPLOT_PLOT_OPTIONS} title '${COL_MEM_SWAP_LABEL}', \
    "${file}" using 1:${COL_MEM_FREE} ${GNUPLOT_PLOT_OPTIONS} title '${COL_MEM_FREE_LABEL}', \
    "${file}" using 1:${COL_MEM_BUFF} ${GNUPLOT_PLOT_OPTIONS} title '${COL_MEM_BUFF_LABEL}', \
    "${file}" using 1:${COL_MEM_CACHE} ${GNUPLOT_PLOT_OPTIONS} title '${COL_MEM_CACHE_LABEL}'
    exit
    GNUPLOT_CMDS
    echo "Memory graph plotted to '${file}.memory.png'"
    }
     
    function plotCpu() {
    local file="${1}"
     
    "${GNUPLOT}" << GNUPLOT_CMDS
    # The paper
    ${GNUPLOT_PAPER}
    set yrange [0:105]
    # The data
    ${GNUPLOT_DATA}
    set output "${file}.cpu.png"
    # Labels
    TITLE = "VMStat CPU"
    YLABEL = "CPU %"
    ${GNUPLOT_LABELS}
    plot "${file}" using 1:${COL_CPU_USER_TIME} ${GNUPLOT_PLOT_OPTIONS} title '${COL_CPU_USER_TIME_LABEL}', \
    "${file}" using 1:${COL_CPU_SYSTEM_TIME} ${GNUPLOT_PLOT_OPTIONS} title '${COL_CPU_SYSTEM_TIME_LABEL}', \
    "${file}" using 1:${COL_CPU_IDLE_TIME} ${GNUPLOT_PLOT_OPTIONS} title '${COL_CPU_IDLE_TIME_LABEL}', \
    "${file}" using 1:${COL_CPU_WAIT_TIME} ${GNUPLOT_PLOT_OPTIONS} title '${COL_CPU_WAIT_TIME_LABEL}'
    exit
    GNUPLOT_CMDS
    echo "CPU graph plotted to '${file}.cpu.png'"
    }
     
    function plotIO() {
    local file="${1}"
     
    "${GNUPLOT}" << GNUPLOT_CMDS
    # The paper
    ${GNUPLOT_PAPER}
    set yrange [0:]
    # The data
    ${GNUPLOT_DATA}
    set output "${file}.io.png"
    # Labels
    TITLE = "VMStat I/O"
    YLABEL = "I/O (blocks/s)"
    ${GNUPLOT_LABELS}
    plot "${file}" using 1:${COL_IO_BLOCKS_READ} ${GNUPLOT_PLOT_OPTIONS} title '${COL_IO_BLOCKS_READ_LABEL}', \
    "${file}" using 1:${COL_IO_BLOCKS_WRITE} ${GNUPLOT_PLOT_OPTIONS} title '${COL_IO_BLOCKS_WRITE_LABEL}'
    exit
    GNUPLOT_CMDS
    echo "I/O graph plotted to '${file}.io.png'"
    }
     
    # The trap ensures that graphs are plotted afterwards and
    # that temporary files get deleted.
    function bashtrap() {
    if ${CREATE_GRAPH} || ${ONLY_CREATE_GRAPH}; then
    plotMemory "${OUTPUT_FILE}"
    plotCpu "${OUTPUT_FILE}"
    plotIO "${OUTPUT_FILE}"
    fi
    if ${IS_TEMP}; then
    echo "Cleaning temporary file at '${OUTPUT_FILE}'"
    rm -f "${OUTPUT_FILE}"
    fi
    }
     
    if ${ONLY_CREATE_GRAPH}; then
    bashtrap
    else
    trap bashtrap TERM EXIT
     
    echo "Starting monitoring. Press Ctrl+C to abort..."
    echo ""
     
    VMSTAT_OPTS="-n" # display header only once
    VMSTAT_OPTS="${VMSTAT_OPTS} -S M" # Memory in Megabytes
     
    COMMAND="vmstat ${VMSTAT_OPTS} 1"
    if [ -n "${REMOTE_HOST}" ]; then
    echo "Observing remote host ${REMOTE_HOST}..."
    COMMAND="ssh ${REMOTE_HOST} ${COMMAND}"
    fi
    echo "Output goes to \"${OUTPUT_FILE}\"..."
    ${COMMAND}|"${AWK}" 'BEGIN { OFS = "," } {$1=$1} NR == 1 { next; } NR == 2 { print "timestamp","date","tod", $0; next; } { print systime(), strftime("%Y-%m-%d,%H:%M:%S"), $0; fflush(); }'|tee "${OUTPUT_FILE}"
    fi
    This looks great, but after creating the CSV, I get:
    # vmload.sh -f vmload.csv -G
    
    gnuplot> TITLE = "VMStat Memory"
                     ^
        line 0: invalid expression
    
    
    gnuplot> YLABEL = "Memory (MB)"
                      ^
         line 0: invalid expression
    
         line 0: undefined variable: TITLE
    
    Althought it does write out vmload.csv.memory.png, but no others. It also happens with -g.
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    2023 Promox on Morefine N6000 16GB 512GB

    2023 Promox on Morefine N6000 16GB 512GB Software Etcher 100MB (not but can be rufus-4.3.exe 1.4MB) Proxmox VE 7.4 ISO Installer (1st ISO re...