#!/bin/sh
start=$(date +%s)
#The thing you want to do
echo "testing the echo duration"
sleep 3
end=$(date +%s)
duration=$(( end - start ))
echo "The total excution time is ${duration} seconds."
最後會印出執行的秒數,如下圖:
#!/bin/sh
start=$(date +%s)
#The thing you want to do
echo "testing the echo duration"
sleep 3
end=$(date +%s)
duration=$(( end - start ))
echo "The total excution time is ${duration} seconds."
最後會印出執行的秒數,如下圖:
今天我想要新增幾個檔案,到root-filesystem當中
於是我在recipe (xxx.bb)的 do_install 裡面加了以下幾行 (綠色字體)
詳細說明:
我想把兩個檔案,regulatory.db 與 regulatory.db.p7s 放到 rootfs 裡面的 /llib/firmware/ 底下
於是我就增加三行
install -d ${D}/lib/firmware
install -m 0644 ${B}/regulatory.db ${D}/lib/firmware/regulatory.db
install -m 0644 ${B}/regulatory.db.p7s ${D}/lib/firmware/regulatory.db.p7s
然後進行編譯,結果出現以下的錯誤訊息(QA Issue)
ERROR: nxp9098-fw-1.0-r0 do_package: QA Issue: nxp9098-fw: Files/directories were installed but not shipped in any package: /lib/firmware/regulatory.db.p7s /lib/firmware/regulatory.dbPlease set FILES such that these items are packaged. Alternatively if they are unneeded, avoid installing them or delete them within do_install. nxp9098-fw: 2 installed and not shipped files. [installed-vs-shipped]
如下圖:
這種錯誤是因為,你install了這些檔案,到root-filesystem,但是你沒把這些檔案一起包到他的package裡面造成的,所以解決方法是,在把這幾個檔案加到FILES_${PN},就可以順利編譯成功了!
因此你需要再加入這兩行到 FILES_${PN},如下圖:
今天有個需求,是必須在chroot當中,執行 power-off
想當然爾,第一個想到的是使用 shutdown now
於是馬上把shutdown 這個指令,移植到 chroot,執行後出現以下的訊息,但無法 poweroff
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
Failed to talk to init daemon
另外也試過,在chroot當中使用 kill -9 1 ,沒有出現錯誤訊息,但是一樣沒作用
(有在chroot當中kill某個 process,ex: kill -9 24, 是可以成功的)
google上面找到一個 /proc/sysrq-trigger 的方法,如下:
Step1:
先執行 echo 1 > /proc/sys/kernel/sysrq
Step2:
poweroff:
=> echo "o" > /proc/sysrq-trigger
reboot:
=> echo "b" > /proc/sysrq-trigger
更多用法可以參考
Ref: http://www.unixlinux.online/unixlinux/linuxjc/gylinux/201703/95680.html
# 立即重新啟動裝置
echo "b" > /proc/sysrq-trigger
# 立即關閉裝置
echo "o" > /proc/sysrq-trigger
# 導出內存分配的信息 (可以用/var/log/message 查看)
echo "m" > /proc/sysrq-trigger
# 導出當前CPU寄存器信息和標志位的信息
echo "p" > /proc/sysrq-trigger
# 導出線程狀態信息
echo "t" > /proc/sysrq-trigger
# 故意讓系統崩潰(kernel panic)
echo "c" > /proc/sysrq-trigger
# 立即重新掛載所有的文件系統
echo "s" > /proc/sysrq-trigger
# 立即重新掛載所有的文件系統為只讀
echo "u" > /proc/sysrq-trigger
Documentation for sysrq.c
Based on kernel version 2.6.38. Page generated on 2011-03-22 22:20 EST.
當有個Daemon占據CPU太多的使用率時,我們可以透過調整nice值來降低其佔據CPU的使用率
今天我們以 mnld 這個daemon來當作範例,mnld是一個GNSS使用的Daemon
說明一下怎麼修改nice數值,也就是調整其優先順序
如下圖,我們可以在系統或是你的 Source Code 當中找到 mnld.service
然後我們可以修改如下圖,Nice值範圍為 -20 ~ 19 (高優先 ~ 低優先),default is 0
改完之後,下次重啟設備,我們可以使用指令,來觀察Nice值 => ps -fl -C "mnld"
command ref:
https://www.thegeekstuff.com/2013/08/nice-renice-command-examples/
Step1:
我使用的Yocto Project為2.6版,編譯SDK的指令如下: (以 MTK平台為例, xxxx 帶入自己的platform)
bitbake mtk-image-xxxx -c populate_sdk
Step2:
用以上指令,編譯出來的Toolchain並不包含kernel header或是 kernel source,查詢網頁之後,得知需要再包含編譯這個Package “kernel-devsrc”
Step3:
接著我們在mtk-image-xxxx.bb 裡面,加上這個package,IMAGE_INSTALL_append += "kernel-devsrc"
Path: meta/meta-mediatek-mtxxxx/recipes-core/images/mtk-image-xxxx.bb
如下圖:
Step4:
接著編譯SDK,會遇到以下的錯誤訊息:
Fix kernel-devsrc package failing during install This issue is due to the upstream script hardcodes /bin/awk whereas we ship /usr/bin/awk. The installation check will break in this case. Fix it by changing the path in the script.
Step5:
從網路上,也看到有人在討論同樣的議題,有人提供patch方法,如下Link:
於是我把這些修改加入meta/meta-mediatek-mtxxxx/recipes-kernel/linux/linux-mtk-extension_4.19.bbappend如下:
Step6:
接著繼續編譯SDK,結果出現以下的問題:
ERROR: mtk-image-xxxx-1.0-r0 do_populate_sdk: Could not invoke dnf. Command
主要的錯誤訊息如下
Error:
Problem: package target-sdk-provides-dummy-1.0-r0.sdk_provides_dummy_target conflicts with /bin/sh provided by busybox-1.29.3-r0.aarch64
- package kernel-devsrc-1.0-r0.autoxxxxevb_ivt_vp2 requires /usr/bin/awk, but none of the providers can be installed
- conflicting requests
Step7:
看了上面的錯誤訊息,其中一個錯誤是說,我們沒有安裝awk這個工具,因此我們試著安裝gawk. 我們接著到Yocto網站master branch底下,poky的路徑底下,搜尋awk
https://git.yoctoproject.org/poky/tree/?id=0a04692279f83637c0049cb1f91ac684f3fccf1f
於是可以看到如下的畫面,接著隨便點一個link,會到下面第二個頁面,我們可以從第二個頁面看到實際gawk的路徑為”meta/recipes-extended/gawk/”
Step8:
接著就可以回到Yocto Tree的路徑,接著按照下圖步驟,可以找到gawk的reciepe.
https://git.yoctoproject.org/poky/tree/meta?id=0a04692279f83637c0049cb1f91ac684f3fccf1f
Step9:
我們選擇使用版本gawk-4.1.3,因為我們的Yocto為2.6版比較舊,選太新的recipe,有語法寫法不相同的問題(ex: gawk-5.x).於是分別把gawk_4.1.3.bb以及 gawk_4.1.3資料夾,放到我們的Yocto Project (這個網站不知道怎麼下載檔案,目前我是用複製內容,再vi gawk_4.1.3.bb 到Yocto Project當中)
path:meta/meta-mediatek-mtxxxx/recipes-extended/gawk_4.1.3.bb
Step10:
另外要記得,還要再從mtk-image-xxxx.bb那邊打開gawk,這樣才會編譯到gawk.去修改meta/meta-mediatek-mtxxxx/recipes-core/images/mtk-image-xxxx.bb
Step11:
再重新編譯一次,就可以成功編譯出包含kernel-devsrc的toolchain
*註:加入kernel-devsrc&gawk之後,整個 編譯後的 image增加了100MB
這邊簡單寫一個example
====== printf.c ========
#include <stdio.h>
int print_hello()
{
printf("This is a simple API example\n");
return 0;
}
寫好這個API source code之後,先編譯出.o檔
gcc -c printf.c -o printf.o -I.
接著把.o檔,轉成.a檔
ar rcs printf.a printf.o
接著就可以寫一個主程式,去呼叫此API
如何使用此 Static Library,使用下面command編譯,可以產生test_main:
gcc main.c printf.a -o test_main -I.
也可以簡單寫一個 Makefile去做編譯(這邊解說Makefile 一小部分)
這邊是順帶的解說 Makefile語法,最主要還是要介紹,怎麼產生像是 printf.a 的 Static Library
###### Makefile 範例解說 #######
my_target: source_file.c header_file.h
gcc -o $@ $< -I.
$@: 表示目標,也就是 "my_target"
$<: 表示第一個依賴文件
mpstat 與 top 指令,都是用來監控 CPU 使用率的工具
mpstat 是 Multiprocessor Statistics 的縮寫,它是 sysstat 這個套件裡面的一個工具
所以當我們要在Yocto裡面開啟這個工具,請記得是開啟 sysstat
如果要使用 mpstat這個工具,也可以用以下的 apt-get指令來安裝
apt-get install sysstat
sysstat 的opensource,我們可以從以下的網站來下載:
https://github.com/sysstat/sysstat
另外簡單介紹一下mpstat的使用方式
直接使用指令 mpstat:
使用指令 mpstat -P ALL 5 2:
參數所代表的意思為
-P ALL: -P表示要監控哪個CPU,這邊帶入ALL,表示列出所有CPU的狀態
5: 表示5秒印出一次
2: 表示印2個回合
假設在bb檔,或是 bbclass檔案裏面,有一些參數,我們會不知道實際的值
這時候,我們可以用 echo 印檔案的方式,導出到 deploy路徑底下的檔案,例如:
在某個bbclass檔案中,我們想知道, ${D} 與 ${STATE_DIR_FILE_PATH},這兩個參數的數值分別是什麼
此時,我們就可以在bbclass 檔案中加入下面兩行
echo ${D} > ${DEPLOY_DIR_IMAGE}/0001
echo ${STATE_DIR_FILE_PATH} > ${DEPLOY_DIR_IMAGE}/0002
最後我們編譯之後,再回到 Yocto Project 底下的這個路徑:
build/tmp/deploy/images/你的platform名稱/
可以找到檔案 0001 與 0002
在使用 cat 把 0001 與 0002 的內容印出來,就可以知道參數的實際數值了!
我之前就有申辦過富邦快樂旅平卡,所以每次要出國申辦旅遊不便險,就很方便
可以依據自己想要投保的金額來選擇,而且不只保自己的,還可以保家人的
以下來介紹一下保旅遊不便險的步驟
如果你沒申辦過快樂旅平卡,你必須先線上申請或臨櫃申請,如下圖:
線上申請網址,請到這個網址:
https://www.fubon.com/insurance/b2c/content/prod_travel_compare/index.html
點選下圖的,我要線上申辦 (不過還是需要列印填寫,並回傳資料)
需特別注意的是,雖然聲稱只需一個小時就可以辦妥旅平險,但申辦旅平卡,需要7個工作天
Step1:
首先會需要填寫,你要保幾天的保險,計算方式說明如下:
*投保單位,以一天為單位
投保日期計算,舉個例子:
假設我的班機時間如下
2024/01/17 16:55 (台灣出發到日本) ~ 2024/01/23 9:00 (日本到台灣)
旅遊地區: 日本
因此可以投保 2024/1/17 16:00 ~ 2024/1/23 16:00 , 共六天
Step2:
選擇大人投保金額,我是選擇100萬方案,詳細內容如下,可以接著點選套用到其他親屬:
今天在做GPIO High/Low的測試,
我有個gpio input mode,我在電路板上面找一個1.8V電壓,外接一條電線
要用這個1.8V去讓GPIO偵測為 input high
硬體工程師說,最好在 GPIO PIN的前面,加入一個電阻,避免電流過大燒壞這個GPIO PIN
加入了之後,我用1.8V去碰觸這個 GPIO,從軟體端印出GPIO狀態,卻沒有被拉High
硬體工程師查了原因,可能因為是在1.8V的路上,有一個電阻
在GPIO PIN的前面,我們又加了一個電阻,造成分壓的情況,
導致電壓值沒有超過 GPIO PIN 所需要的上拉電壓值 (此數值需要看 GPIO Spec,這裡為1.3V)
分壓概念圖,大致如下:
另外分享一個分壓的計算網站,帶入你的每個電阻阻值,可以幫你算分壓
https://www.digikey.tw/zh/resources/conversion-calculators/conversion-calculator-voltage-divider
之前一直從 google search console 要去解決無法被搜尋的問題
總是卡在 sitemap 的問題上,我在新增Sitemap 的部分,輸入我的blog 網址之後 ,點選提交,如下圖:
但審核總是有問題,大概的問題如下所示:
結果我發現,其實在新增Sitemap的時候,似乎要輸入 URL+"Sitemap.xml" 就可以成功,如下:
https://gigidandan.blogspot.com/sitemap.xml
後來我就可以看到,提交成功,還可以看到索引的網站個數:
我只能說,如果你們搜尋到我的這篇文章的話,就表示我這個修改方法成功了!
:D
#先把ethernet0 停用
ifconfig eth0 down
#更改MAC Address
ifconfig eth0 hw ether AA:BB:CC:DD:EE:FF
#啟用ethernet0
ifconfig eth0 up
#最後在使用ifconfig 檢查
ifconfig
這邊先記錄debug的方式
我們可以在Linux作業系統底下,使用這個command
=> export GST_DEBUG="*:6"
實驗1:
我們使用gstreamer的debug mode發現幾件事情
1. 執行 get-lauch-1.0 之後,會在檔案系統中產生名為 “registry.aarch64.bin”的檔案
2. 這個cache檔案存放在 /home/root/.cache/gstreamer-1.0/
接著我們寫了簡單的script,會去執行這個command
=> /usr/bin/gst-launch-1.0 filesrc location=/etc/Track.awb ! decodebin ! audio convert ! audio resample ! audio/x-raw,rate=48000,channels=2,format=S16LE ! volume volume=2 ! alsasink device="hw:0,0"
接著我們計算有cache檔案的執行時間,去比較沒有cache檔案的執行時間
=> 有cache: 0.2 sec 沒有cache: 1 sec (計算時間方式,使用teraterm的timestamp 去計算)
實驗2:
事先儲存好這個cache檔,重新更新這個device的韌體,刷新後把cache檔案放到 /home/root/.cache/gstreamer-1.0/
結果會跟實驗1當中,有cache的結果一樣,約執行0.2秒
今天電視突然無預警的沒有畫面,關閉電源再度開啟後,電視綠燈恆亮
按電源按鈕開啟電視,都沒有反應,這台電視才使用4年,想說會不會是主機板的電源管理部分出了問題,於是上網找了一些資訊
這台電視,只有一個主機板 + 邏輯版,主機板的部分,是三合一板 (),把電源板與主機板合在一起,然後找到下面方法,試了之後,還真的讓我的螢幕亮了起來
接著按下電源按鈕之後,就可以讓電視回到紅燈狀態,資訊與步驟如下:
夏普液晶電視的很多機型主板有5次記憶保護,當背光或者電源發生故障時,只要開機5次以上,就形成保護記憶,解除方法步驟如下
Step1: 按住 信號源鍵(INPUT/AV/TV) 與 音量減鍵,同時拔掉電源插頭
Step2: 之前按住的鍵,到這步驟都不要放開,再度插上電源插頭
我完成以上兩個步驟後,電視就恢復正常了~ 不用花大錢了 :D
2023/11/09 更新最新狀況,後來還是遇到綠燈恆亮問題,上蝦皮買了一塊二手主機板 $1200
自行拆開更換後,正常服役中~
之前有寫了一篇 ALSA API 實作amixer command: amixer -c0 set i2s_clock on
後來發現,有兩個 Bug 需要被修正,分別如下:
1. 第一次如果使用 i2s_clock off,會造成 kernel 端出現 core_dump 錯誤,導致執行時間會變很長 (原本大概只需要 20ms,結果時間拉長到 200ms)
2. 發現這個上層的API程式,呼叫Linux Kernel 層,去triger I2S,出現 non-blocking的現象(application 呼叫底層程式,但沒有等待底層做完,就直接繼續執行application層的事情)
因此加入底下一些程式,來解決這兩個問題 (用不同顏色標出)
#include <stdio.h>
#include <alsa/asoundlib.h>
int set_mixer_onoff(const char *control_name,
int option)
{
const char *device = "hw:0"; // 音訊設備的名稱或識別符號
//const char *control_name = "i2s_clock"; // 控制元素的名稱, 由API參數帶入
snd_ctl_t *handle;
snd_ctl_elem_id_t *elem_id;
snd_ctl_elem_value_t *elem_value;
int err;
int ori_value;
int i2s_is_set = 0;
// 打開音訊設備的控制界面
err = snd_ctl_open(&handle, device, 0);
if (err < 0) {
printf(":Cannot open device interface: %s\n", snd_strerror(err)); //無法打開音訊設備的控制界面
return err;
}
// 分配並初始化 snd_ctl_elem_id_t 結構
snd_ctl_elem_id_alloca(&elem_id);
snd_ctl_elem_id_set_name(elem_id, control_name);
// 獲取控制元素的索引
snd_ctl_elem_id_set_interface(elem_id, SND_CTL_ELEM_IFACE_MIXER);
// 獲取控制元素的數值
snd_ctl_elem_value_alloca(&elem_value);
snd_ctl_elem_value_set_id(elem_value, elem_id);
snd_ctl_elem_value_set_boolean(elem_value, 0, option); // 設置boolean值,由API參數option帶入
// This is for fixing the core_dump issue
// 先取得之前狀態,如果跟這次要設定的狀態相同,就不需要再做,直接 return.
err = snd_ctl_elem_read(handle, elem_value);
if (err < 0) {
printf("Cannot read value: %s\n", snd_strerror(err));
snd_ctl_close(handle);
return err;
}
ori_value = snd_ctl_elem_value_get_
if( option == ori_value )
{
printf("No need to Set, option equal to ori_value\n");
snd_ctl_close(handle);
return 0;
}
else
snd_ctl_elem_value_set_
//////////////////////////////
// 設置控制元素的數值
err = snd_ctl_elem_write(handle, elem_value);
if (err < 0) {
printf("Cannot set value: %s\n", snd_strerror(err)); //無法設置控制元素的數值
snd_ctl_close(handle);
return err;
}
// Poll the control value until it reaches the desired state
// For fix the non-blocking issue
while (!i2s_is_set) {
// Sleep for a short period to avoid busy-waiting
usleep(5000); // Sleep for 5 milliseconds
// Read the control value
err = snd_ctl_elem_read(handle, elem_value);
if (err < 0) {
printf("Cannot read value 2th: %s\n", snd_strerror(err));
snd_ctl_close(handle);
return err;
}
// Check if the control value is equal to the desired state
int cur_value = snd_ctl_elem_value_get_
if (cur_value == option) {
i2s_is_set = 1;
}
}
// 關閉音訊設備的控制界面
snd_ctl_close(handle);
printf("Setting %s %d success\n", control_name, option); //已成功設置 i2s_clock 為 on
return 0;
}
這個範例,計算單位為 microSecond(10-6)
#include <time.h>
clock_t start, end;
double cpu_time_used;
printf("** Start to measure time **\n");
start = clock();
...
...
...
end = clock();
cpu_time_used = ((double) (end - start))*1000000 / (CLOCKS_PER_SEC);
printf("** execution time:%f microseconds\n", cpu_time_used);
printf("** End of measure time **\n");
首先需要 include 這個 header file
#include <linux/time.h>
然後使用下面的方式,搭配 printk 在kernel 端印出計算時間,
這邊我們取 microseconds (10-6)
struct timeval start_time, end_time;
unsigned long elapsed_time;
printk(KERN_ERR "#### measure time start %s ####\n", __func__);
do_gettimeofday(&start_time);
...
...
...
do_gettimeofday(&end_time);
// Calculate the executing time
elapsed_time = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
(end_time.tv_usec - start_time.tv_usec);
printk(KERN_ERR "#### Elapsed time: %lu microseconds\n", elapsed_time);
printk(KERN_ERR "#### measure time end %s ####\n", __func__);
另外在 kernel 較新的版本當中,如果 do_gettimeofday() 無法使用,可以試試看下列方法
#include <linux/ktime.h>
#include <linux/types.h>
ktime_t start, end;
s64 elapsed_ns, elapsed_us;
start = ktime_get();
...
...
...
end = ktime_get();
elapsed_ns = ktime_to_ns(ktime_sub(end, start));
elapsed_us = ktime_to_us(elapsed_ns );
printk(KERN_ERR "#### Elapsed time: %lld microseconds\n", elapsed_us);
在網路上查詢了很久,總算找到了一個解法
並且讓我的舊平板電腦,也可以上 YouTube看影片
NewPipe 是一個 Open source,如果你的Android 是 4.2.2 (低於 Android 4.4)
可以到以下的網站,下載 NewPipe Legacy (0.20.8版)
https://f-droid.org/packages/org.schabi.newpipelegacy/#latest
If your device is Android 4.2.2 and cannot successfully use the YouTube, you can install the "NewPipe Legacy" APK.
The NewPipe Legacy is an open source. After I install into my Table computer, the YouTube can work now. You can use your Table computer and click the following link. Then download the version 0.20.8, this should be work.
Best Regards!
當在我們的device端,可以使用命令 "amixer -c0 set i2s_clock on" 來開啟 i2s_clock
也可以使用命令 "amixer -c0 set i2s_clock off" 來關閉 i2s_clock
這表示我們的device 底層,已經有建立 "i2s_clock" 這個kcontrol,因此我們使用amixer 命令,才可以順利的再取呼叫到kcontrol所定義好的 function,進而做到function裡面所實作好的行為
簡單的kcontrol,大概如下圖所示: (此範例為MTK mt6880 audio card)
*註 SOC_SINGLE_EXT 是Linux底下的巨集,想知道定義可以去kernel底下 include/sound/soc.h 查看
以上簡單描述一下kcontrol,接下來進入本文章的主題,如何使用ALSA API來實作一個API,讓別人呼叫此API,就達到跟 amixer command 一樣的行為,底下是一個簡單的實作範例
#include <stdio.h>
#include <alsa/asoundlib.h>
int set_mixer_onoff(const char *control_name,
int option)
{
const char *device = "hw:0"; // 音訊設備的名稱或識別符號
//const char *control_name = "i2s_clock"; // 控制元素的名稱, 由API參數帶入
snd_ctl_t *handle;
snd_ctl_elem_id_t *elem_id;
snd_ctl_elem_value_t *elem_value;
int err;
// 打開音訊設備的控制界面
err = snd_ctl_open(&handle, device, 0);
if (err < 0) {
printf(":Cannot open device interface: %s\n", snd_strerror(err)); //無法打開音訊設備的控制界面
return err;
}
// 分配並初始化 snd_ctl_elem_id_t 結構
snd_ctl_elem_id_alloca(&elem_id);
snd_ctl_elem_id_set_name(elem_id, control_name);
// 獲取控制元素的索引
snd_ctl_elem_id_set_interface(elem_id, SND_CTL_ELEM_IFACE_MIXER);
// 獲取控制元素的數值
snd_ctl_elem_value_alloca(&elem_value);
snd_ctl_elem_value_set_id(elem_value, elem_id);
snd_ctl_elem_value_set_boolean(elem_value, 0, option); // 設置boolean值為1,由API參數帶入
// 設置控制元素的數值
err = snd_ctl_elem_write(handle, elem_value);
if (err < 0) {
printf("Cannot set value: %s\n", snd_strerror(err)); //無法設置控制元素的數值
snd_ctl_close(handle);
return err;
}
// 關閉音訊設備的控制界面
snd_ctl_close(handle);
printf("Setting %s %d success\n", control_name, option); //已成功設置 i2s_clock 為 on
return 0;
}
最後,編譯成為Library之後,提供對方 library 以及 xxx.h 裡面有包含此API宣告
int set_mixer_onoff(const char *control_name, int option);
對方就可以使用了!
此篇直接介紹 cpulimit 該如何使用,讓我們做stress-test 可以直接指定想要的CPU Loading
先假設我們的設備為 雙核心(dual-core)的device
我們先撰寫一個loop的shell script,這個script可以把一個CPU使用率,占用到100%
====== loop_1.sh ======
#!/bin/sh
while [ 1 ]
do
echo 5566 > /dev/null
done
====================
上面這個簡單的小程式,就可以占用100%的一個CPU使用率
所以如果是雙核心的device,很簡單,我們就再搞一個loop script
====== loop_2.sh ======
#!/bin/sh
while [ 1 ]
do
echo 5566 > /dev/null
done
====================
接著我們再去撰寫一個主要的shell script,可以帶起 loop_1.sh 與 loop_2.sh
並且會去使用 cpulimit 去限制這兩個 loop程式的 cpu 使用率
進而達到我們想要維持的 CPU 使用率
====== cpuload.sh =======
#!/bin/sh
if [ "$#" -lt "1" ]; then
echo "ex: ./cpuload.sh 40 (limit at 40%)"
exit
fi
VAL=$1
killall loop_1.sh loop_2.sh
./loop_1.sh &
L1=`ps | grep loop_1.sh | awk -F ' ' '{print $1}'` #get pid
./loop_2.sh &
L2=`ps | grep loop_2.sh | awk -F ' ' '{print $1}'` #get pid
./cpulimit --limit=$VAL --pid=$L1 &
./cpulimit --limit=$VAL --pid=$L2 &
=======================
今天要跟大家介紹一個好用的工具,可以限制某一個Process只允許他使用多少的CPU Loading
另外,如果要做壓力測試(stress test),只要稍微再搭配一些自己撰寫的shell script
可以達到自行指定壓力測試所要的cpu loading
先介紹這個open source,名為 "cpulimit",source code link如下:
https://github.com/opsengine/cpulimit
如果要在你的平台上,作壓力測試,請先自行做 Cross Compile,這邊先簡單教你如何編譯出你平台可以使用的tool
我們可以看到此opensouce的目錄結構如下圖:
Step1:
在你下載好的source code,如上圖的路徑底下,先指定好你的CC環境變數
ex: 我要編譯電腦x86 用的tool,我的Toolchain就會是 /usr/bin/gcc,於是我用以下方式指定CC
=> export CC=/usr/bin/gcc
Step2:
執行make,就可以成功編譯出我們要的工具,"cpulimit"
(如果要重新編譯,記得先make clean)
Step3:
編譯出來的執行程式,會在cpulimit-master/src/ 路徑底下,如下圖:
Step4:
執行cpulimit,可以看到使用方式,如下圖:
我們主要會用到 limit 與 pid 這兩個參數
下一篇文章,再來繼續介紹,怎麼加一些shell script,來做到壓力測試!
今天要記錄一個小數點運算的 shell script 範例
我們要把12去除以10,然後要得到值1.2,實際範例如下:
########## Floating point operation #############
#!/bin/sh
VAL=12
VAL=`echo | awk "{print $VAL/10}"`
echo "VAL=$VAL"
結果:
永豐大戶的銀行APP, 目前需要重新綁定裝置
目前有兩種方式可以來綁定
1. 直接APP內操作綁定:
如果你的手機SIM卡,電話號碼與你當初申請的號碼是同一個,可以直接使用APP,按照APP建議的步驟來做APP與手機綁定
2. 透過永豐的網頁版,網路銀行來做裝置綁定:
如果你有兩個門號,A與B門號,當初申請永豐是用A門號,而你目前常用的手機是B門號,就需要用這個方式來綁定你B門號的手機
做這個動作,你必須要有電腦,讀卡機,以及永豐金融卡(白色那張),來做認證
步驟如下:
a. 到MMA金融交易網,登入網路銀行,網址如下:
https://mma.sinopac.com/MemberPortal/Member/NextWebLogin.aspx
b. 登入之後,選擇"申請/設定",管理我的行動裝置
下面介紹一個範例程式名為 "signal",編譯此程式之後,把此程式run在背景,可以使用下面幾個指令,來觸發此程式當中的 printf來印出相對應的訊息,當然你也可以把 printf 改成你想做的事情
kill -SIGHUP `pidof signal`
kill -SIGINT `pidof signal`
kill -SIGQUIT `pidof signal`
======================= signal.c =================
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void sigroutine(int sig_num) {
switch(sig_num) {
case 1:
printf("Get a signal - SIGHUP \n");
case 3:
printf("Get a signal - SIGQUIT \n");
case 10:
printf("Get a signal - SIGUSR1 \n");
}
return;
}
int main() {
printf("process id is %d\n", getpid());
signal(SIGHUP, sigroutine);
signal(SIGQUIT, sigroutine);
signal(SIGUSR1, sigroutine);
for (;;) ;
}
==============================================
另外列出,所有可以帶入 kill 後面的sigmal列表(Reference from google)
2 - 就是我們常見的鍵盤中斷 CTRL+c
9 - 就是我們常用來kill process的 signal
信號 | 取值 | 默認動作 | 含義(發出信號的原因) |
---|---|---|---|
SIGHUP | 1 | Term | 終端的掛斷或進程死亡 |
SIGINT | 2 | Term | 來自鍵盤的中斷信號 |
SIGQUIT | 3 | Core | 來自鍵盤的離開信號 |
SIGILL | 4 | Core | 非法指令 |
SIGABRT | 6 | Core | 來自abort的異常信號 |
SIGFPE | 8 | Core | 浮點例外 |
SIGKILL | 9 | Term | 殺死 |
SIGSEGV | 11 | Core | 段非法錯誤(內存引用無效) |
SIGPIPE | 13 | Term | 管道損壞:向一個沒有讀進程的管道寫數據 |
SIGALRM | 14 | Term | 來自alarm的計時器到時信號 |
SIGTERM | 15 | Term | 終止 |
SIGUSR1 | 10 | Term | 用戶自定義信號1 |
SIGUSR2 | 12 | Term | 用戶自定義信號2 |
SIGCHLD | 20,17,18 | Ign | 子進程停止或終止 |
SIGCONT | 19,18,25 | Cont | 如果停止,繼續執行 |
SIGSTOP | 17,19,23 | Stop | 非來自終端的停止信號 |
SIGTSTP | 18,20,24 | Stop | 來自終端的停止信號 |
SIGTTIN | 21,21,26 | Stop | 後台進程讀終端 |
SIGTTOU | 22,22,27 | Stop | 後台進程寫終端 |
SIGBUS | 10,7,10 | Core | 總線錯誤(內存訪問錯誤) |
SIGPOLL | Term | Pollable事件發生(Sys V),與SIGIO同義 | |
SIGPROF | 27,27,29 | Term | 統計分佈圖用計時器到時 |
SIGSYS | 12,-,12 | Core | 非法系統調用(SVr4) |
SIGTRAP | 5 | Core | 跟踪/斷點自陷 |
SIGURG | 16,23,21 | Ign | socket緊急信號(4.2BSD) |
SIGVTALRM | 26,26,28 | Term | 虛擬計時器到時(4.2BSD) |
SIGXCPU | 24,24,30 | Core | 超過CPU時限(4.2BSD) |
SIGXFSZ | 25,25,31 | Core | 超過文件長度限制(4.2BSD) |
SIGIOT | 6 | Core | IOT自陷,與SIGABRT同義 |
SIGEMT | 7,-,7 | Term | |
SIGSTKFLT | -,16,- | Term | 協處理器堆棧錯誤(不使用) |
SIGIO | 23,29,22 | Term | 描述符上可以進行I/O操作 |
SIGCLD | -,-,18 | Ign | 與SIGCHLD同義 |
SIGPWR | 29,30,19 | Term | 電力故障(System V) |
SIGINFO | 29,-,- | 與SIGPWR同義 | |
SIGLOST | -,-,- | Term | 文件鎖丟失 |
SIGWINCH | 28,28,20 | Ign | 窗口大小改變(4.3BSD, Sun) |
SIGUNUSED | -,31,- | Term | 未使用信號(will be SIGSYS) |
另外在Linux底下,輸入 kill -l 也可以看到這些SIGXXX 所定義的編號,如下:
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1
36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5
40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9
44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13
52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9
56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5
60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1
64) SIGRTMAX
使用以下的command可以印出 eMMC的 partition資訊 lsblk --bytes --output name,partlabel,size 參數說明 --bytes: partition的大小,以byte的方式輸出 --output: 後面可以指定要輸出的內容...