2012年12月14日 星期五

使用python自動回應php網頁

一、緣起:

這篇文的緣起是這樣的:修了一門課要交作業,要從server上把資料下載下來,剖析資料之後建立模型,把模型回傳給server,server會再產生資料。
以上的上傳下載要重複幾次,server的介面是利用php寫的。
這時候又回到我的哲學了:Working hard, after you know you are working smart.
手動下載、建模型、上傳,這並不是個smart的工作方式其一:來回數次用人做本來就慢;其二:也是最重要的一點,人做容易出錯,出錯就會GG要重做。Smart的工作方式不應該是這樣。


二、解決方案:

經過一些調查,我使用的是python urllib module,這是個超完整的python web module,於是就用這個來寫寫看。

問題一:用python來取得 html?
這部分urllib老早就寫好了,用如下的code,下面一行就可以把整個html以bytes的方式取出來: html = urllib.request.urlopen(hw_url).read()
如果要寫入檔案,在開檔的時候指定為'wb'就可以直接將html 寫到檔案中而不怕格式錯誤。 否則就要呼叫.decode(“utf-8”)的方式先轉換html的格式。
針對form filling的部分也有相對應的方式,可以用下面的方式把POST的訊息編碼,在urlopen的時候附加在後面。
data = {}
data['id'] = ID
form_data = urllib.parse.urlencode(data)
form_data = form_data.encode('utf-8') # data should be bytes
response = urllib.request.urlopen(php_url, form_data)
得到是相同可以用read()取得資料的方式,實地驗證過,會得到一個相同的html file。

問題二:取得最新的資料 - 使用正規表示法:
現在有了取得的html檔之後,要怎麼找出其中的連結? 這裡用上了regular expression module re的方式,這大概是地表上最強大的字串比對工具。 該網頁中的檔案下載連結類似這樣的格式
<a href=\'LOL/XD.txt\'>
只要parse <a href>的標籤,很容易就能找到所有的連結檔了
links = re.findall(“<a\s+href\s*=\s*'(.*)'”, data, re.DOTALL)\
其中()就是我們要尋找的目標,會被存入links之中,成為一個list object,取出最後一個連結,就是我們要的最新版本的檔案了。
另一方面,當使用者要使用這個程式時,會需要輸入他們的學號以供使用,這部分也是使用re module來進行檢查:
re.match(“\s*[A-Za-z][0-9]{7,7}\s*”, string)
不match的話就會回傳None,讓程式再進行一次問話。

問題三:如何執行本地程式?
這個倒比較簡單,使用python subprocess即可簡單完成:
command = "./{0}".format(program_name)
 stdout = subprocess.check_output(command.split())

問題四:如何透過php上傳檔案? 這地方問題就頭大了,查了很久一直不知道該怎麼寫比較好。後來是經強者我同學的提示,用的解決方案是httplib的解決方式: http://stackoverflow.com/questions/1270518/python-standard-library-to-post-multipart-form-data-encoded-data
很有趣的是,httplib的運作是先讀入根目錄,再由selector去要求根目錄下的某個檔案。
fields的部分為二元tuple組成的table,tuple前都為要填入form的name attribute,請愛用「觀看原始碼」自行找出對應的name attribute;
後者為要填入的值,例如fields = [(“name”,”yodalee”),(“nickname”,”garbage”)]
files的部分則是三元的tuple,依序為form的name attribute、filename、file的binary;第三個用open(file, 'rb')傳入即可;例如files = [(“model”, “test.txt”, open(“test.txt”, “rb”))] 

當個例子的code如下:
fields = [("id",ID), ("model_submit","")]
files = [("model", filename, open(filename, "rb").read())]

content_type, body = encode_multipart_formdata(fields, files)
h = httplib.HTTP(host)
h.putrequest('POST', selector)
h.putheader('content-type', content_type)
h.putheader('content-length', str(len(body)))
h.endheaders()
h.send(body)
errcode, errmsg, headers = h.getreply()
return h.file.read()
在id的欄位填入ID,model_submit欄位填入空白。
檔案則上傳filename所指的檔案。
上傳檔案,並取得結果存入h之中。

三、結論:

我只需要下個指令,就能把作業所有需要的檔案都準備完成,打包一下,作業就被秒殺了。雖然說我寫python code的時間其實遠超過我手動執行的時間,但整體而言輕鬆很多,這才是working smart!


 四、參考資料:

python urllib manual:
http://docs.python.org/3/howto/urllib2.html
httplib upload files(answer 2):
http://stackoverflow.com/questions/1270518/python-standard-library-to-post-multipart-form-data-encoded-data


五、致謝:

有關python httplib的使用,感謝AZ Huang同學的提點。
作業的部分,感謝Godgodmouse同學的指導。

2012年11月25日 星期日

將sonnet檔轉換到virtuoso上

做高頻電路討厭的就是,頻率太高的情況下,寄生的電容電感會在電路各處藏汙納垢(XD)。
所以在設計的過程,就需要跑很多電磁模擬,把這些寄生的效應一併考慮到模擬之中。
(會吃你一堆電腦的記憶體跟花一堆時間,這也是我為什麼有時間打這篇文章的原因,哈哈)
麻煩就在於,每次在電磁模擬軟體(實驗室用Sonnet)上畫完架構,然後開始跑,確定結果沒錯之後,又要在電路下線的軟體(實驗室用Virtuoso)上畫一遍。
最近學到,該怎麼把sonnet上的檔案匯到virtuoso上面,在這裡記錄一下。

理論上,我們只要把sonnet檔案匯出到GDSII檔,這是IC layout通用格式,幾乎所有的工具都支援;之後再從virtuoso讀入GDSII檔案即可。
遇到的麻煩是,在進行電磁模擬時,我們會在sonnet裡面建好電路一層一層的架構,但Virtuoso的環境卻是依所用的製程而定,它完全看不懂我們是在講什麼?
所以如果直接匯入的話,就會變成有些層virtuoso不知道該對應給誰,變得完全無法編輯,總之會出現各式各樣的問題。
幸好Virtuoso並沒有這麼笨,在匯入檔案的選項中,可以自行指定層與層的Map file,透過這個,理當能「無損的」將sonnet檔案匯入virtuoso中。

1. sonnet to GDSII:
在sonnet中,是將電路板切成一層一層不同的介質,然後可以在每層介質中填入金屬,去摸擬其中的電磁效應,我們要的就是這金屬的pattern。
下面是一個sonnet層數設定的截圖,從最上面的空氣……到最底層的substrate

合理的推斷,GDSII也是將一層一層的資料給記錄下來,但要怎麼知道?
我用的是開源的klayout打開gds下去看,得到如下的畫面:

發現到sonnet轉gds的規則很簡單,原本在sonnet設在第幾層的金屬,就會被轉到gds第幾層;很可惜的,sonnet中層與層間連接的via的資訊全都消失了,不過很多金屬不用重畫還是可以省下很多時間。

 2. GDSII to Virtuoso:
有了上面的資料之後,再來就是編寫map file: 一個map file 的格式如下:
#Cadence layer name  Cadence layer purpose Stream layer number Stream data type
#
TopMetal2 drawing 0-63 0-63

每一行分為四個子資料,分別是:在此製程中的某層的名稱;該層的用途;對應在stream檔中的層數;該層的資料。
像上面這種寫法,會把0-63層的資料都變成TopMetal2。
purpose的部分,大概有drawing, pin, net三種可以選擇,但從sonnet過來的話大概都是要要轉成drawing的。
stream layer number就是方才用klayout看到的layer編號;stream data type這部分則不是很清楚,但sonnet轉出來好像也不會特別去設定。
根據上面的轉出來的資料,可以自行編寫對應的map,data type不清楚就用0-63全部截下來:
#Cadence layer name  Cadence layer purpose Stream layer number Stream data type
#
TopMetal2 drawing 2 0-63
TopMetal1 drawing 3 0-63
MIM drawing 4 0-63
Metal5 drawing 6 0-63
Metal1 drawing 10 0-63
這樣各層就能夠轉換成功了:


不過另一方面,據說從sonnet匯入virtuoso時,有機會發生一些off-grid的問題,這就是一時之間無法解決的問題了。

結論:
這篇介紹了如何將電磁模擬軟體Sonnet上的繪圖,直接轉換到Cadence Virtuoso上面,我很喜歡 「work hard, after you know you are working smart」類似的話
如果可以直接匯入圖形(work smart),就不要花時間重畫(work hard)了。
理論上如果你用的是Sonnect V13以上的話,其實Sonnet已經含有和Virtuoso的介面了。 http://www.sonnetsoftware.com/products/sonnet-suites/ef_translators_cvbridge.html

參考資料:
1. GDSII format description: http://www.buchanan1.net/stream_description.shtml
2. Layermap format description:
http://www-bsac.eecs.berkeley.edu/~cadence/tools/layermap.html
3. open source gds editor, klayout:
http://www.klayout.de/

2012年11月16日 星期五

放大器的級間穩定

做多級的RF的放大器時,除了看一般的stability factor K值外,還需要去測試電路每級放大器的級間穩定。
實驗室一直遵照學長流傳下來的投影片:將電路從中切開,一邊看stability circle,另一邊看ADS裡面的「Map1 circle」跟「Map2 circle」這個東西,然後看看兩個圓有沒有相交在一起,可是這個Map 1/2 circle是啥鬼東西?極間穩定又是什麼?

1. 極間穩定的意義:


先考慮上圖的模型,在一個主動的電晶體兩旁接上matching的電路,stability circle的定義是,在什麼樣的$\Gamma_L$(or $\Gamma_S$)下,會讓$\Gamma_{in}$(out) >1,在$\Gamma_{in}$(out) > 1時,電路幾乎確定會不穩定,將$\Gamma_{in}$(out)=1的邊線畫出來的圓,就是穩定圓(stability circle)。
電路設計完後,一定會看看stability factor K是否全頻帶都大於1,就是要確認電路整體的$\Gamma_{in}$(out)都在穩定的範圍內。
可是若我們把電路切開,這個模型就不適用了,前後接的不是被動的matching電路,這時候我們就要確保,前端的load stability circle,和向後端可能看到任何一點阻抗,都不會相交;否則很不巧的該阻抗出現,電路就不穩定了;這就是極間穩定背後的原理。

所以說map1/2 circle是啥鬼?從上面的定義來看,我認為它所畫的是:當source(load)呈現任何被動阻抗時(也就是實部小於一,落在smith chart上的任何阻抗),會在另一邊load(source)上呈現的阻抗。
實際用複數變換來驗證看看:
$\Gamma_{in} = w = \frac{a \Gamma_L+b}{c\Gamma_L+d}$
改換上式為下式,兩行的abcd並不是相同的:
$\Gamma_L = \frac{a \Gamma_{in}+b}{c \Gamma_{in}+d}$
a=1, b= $-S_{11}$, c= $S_{22}$, d= $-\Delta$
其中 $\Delta = S_{11}S_{22}-S_{12}S_{21}$
這個 $|\Gamma_L|=1$經轉換後會畫出一個圓,其圓心和半徑為:
$C_L = \frac{c^*d-a^*b}{a^2-c^2} = \frac{-S_{11}|S_{22}^2|+S_{12}S_{21}S_{22}^*+S_{11}}{1-|S22|^2} = S_{11}+\frac{S_{12}S_{21}S_{22}^*}{1-|S22|^2}$
$r = \frac{ad-bc}{a^2-c^2} = |\frac{S_{12}S_{21}}{1-|S22|^2}|$
若兩圓相交,就表示有load會讓$\Gamma_L$呈現某阻抗,而該阻抗會落在不穩定圓中,也就使電路在這級不穩定(新細明體:你死了Q_Q)

2. 實際資料:

Linux有問題先查manpage,ADS遇到鬼先問F1 help,結果help裡面解釋是這麼寫的:
Used in Small-signal S-parameter simulations: The function maps the set of terminations with unity magnitude at port 1 to port 2. The circles are defined by the loci of terminations on one port as seen at the other port. A source-mapping circle is created for each value of the swept variable(s). This measurement is supported for 2-port networks only.
大概的意思是一樣的,依著help的註解找到了計算的ael原始碼,下面是map2的原始碼:
defun map2_center_and_radius(sParam, center, radius)
{
    decl S12xS21 = sParam(1,2)*sParam(2,1);
    decl s11MagSq = pow(abs(sParam(1,1)),2);
     *center = sParam(2,2)+S12xS21*conj(sParam(1,1))/(1-s11MagSq);
     *radius = abs(S12xS21)/(1-s11MagSq);
}
可見所做的是以$S_{11}+\frac{S_{12}S_{21}S_{22}^*}{1-|S22|^2}$為圓心,$|\frac{S_{12}S_{21}}{1-|S22|^2}|$為半徑的圓,和我們所計算的結果相符。

附件:

如何在blogger裡面插入方程式?目前找到兩種解決方案
第一種是用這篇文章中所建議的方式:
http://www.codecogs.com/latex/integration/blogger/install.php
照著裡面的步驟做即可,不過它是將LaTeX轉成圖片,再替換掉原本的文字,所以很醜...
而且測試發現Firefox會當掉(媽的連IE都可以了…),原因不明。
第二種是現在的作法:
方法同上,但code是在下面這個blog裡面找到的
http://aishuxue.blogspot.tw/2012/01/latex-blogspot.html

<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js" type="text/javascript">
MathJax.Hub.Config({
 extensions: ["tex2jax.js","TeX/AMSmath.js","TeX/AMSsymbols.js"],
 jax: ["input/TeX", "output/HTML-CSS"],
 tex2jax: {
     inlineMath: [ ['$','$'], ["\\(","\\)"] ],
     displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
 },
 "HTML-CSS": { availableFonts: ["TeX"] }
});
</script>
這個結果超漂亮的啊!!!,實在太強了!
在chrome跟firefox裡面都可以用,IE我倒不知道,反正懶得理他。

致謝:

本篇文章感謝503實驗室強者我同學曾奕恩,以及強者我學長陳柏翰學長在複數變換方面的指導。

2012年11月13日 星期二

c++ static 修飾詞

最近寫基因演算法的project,有需要使用到C++ class的static variable,因為我之前這個東西怎麼寫都會出錯,這次好不容易在強者陳仕勳(GodGodMouse)的指導下成功寫出可以用的static,在這裡記錄一下怎麼使用C++的Static(是說這些文章也多到滿出來了)。

靜態物件static的標記包括:在主體程式中使用,在函式中使用,和在class中作為靜態資料使用。
總歸三種使用方式,都是要在程式的各處中使用共有的一份資料,下面針對三種使用方式,分別寫明使用方法及使用的時機: 

1. Main程式:

在global 的地方使用static,可以讓該變數由程式的全域變數變成檔案內的全域變數,使用static的全域變數幾乎永遠是好習慣,畢竟其他程式設計師在用你的程式時只想把你的程式當黑箱子,要是哪個全域變數名字相衝……那大概不是一兩個幹字可以解決的問題,例如下文中的debug變數,我每個檔案都想要有debug變數,這時就要加上static。
簡單的例子,我們幾個cpp檔裡面都有一個debug變數(總不能main裡的叫maindebug,gui裡的叫guidebug吧?),如果不加上static
//main.cpp
int debug  = 0; 
//src1.cpp
int debug  = 0; 
這樣在最後編譯的時候,g++ main.o src1.o的階段,就會回傳錯誤,因為debug在這裡被重複定義。 因此,請為全域變數加上static。
Static int debug = 0
或者,與static相對的就是extern,宣告變數是在別的檔案裡有定義,這時候不能再給初始值(因為初始值是從別的檔案來的):
extern char* filename;

2. 在函數裡使用:

在函數裡加上static的變數,不同於一般的變數「在函數執行時起始,於函數終結時清除」,static變數在程式一執行時即被宣告。我想這個已經芭樂到不能再芭樂的地步了,例子也不勝枚舉,如果我們要輸出某函數被call幾次,請愛用static。
Void function(){
 static int i=0;
 cout << ++i << endl;
}

3. 在class裡使用:

在class裡使用,其功用在於,這個class產生的任何一個object(or instance if you like),都可看到static的變數或函數。 比如說我project寫的基因演算法的程式,經由隨機產生了10000個子代,每個子代都要對某一筆測試資料進行處理,看看結果好不好;這時候當然不可能每一個子代都保留一份測試資料的副本(記憶體不用錢也不是這樣花的吧…),就要用static的方式保存資料,讓每個子代都能看到。
在class裡面用會複雜一點,假設現在有一個叫static_test的class,架構如下:
//static_test.h
class static_test { 
public:
    static int static_var;
    static void output();
    int i;
};
所以我們宣告了一個static的integer跟一個static 的function,在.h宣告中,大部分的東西是一樣的。
但在定義式裡,就有些不同,由於static物件在是class共有的一部分,宣告class物件時並不會初始化static的物件,因此在.cpp裡面第一件事就是先初始化static物件:
//static_test.cpp
int static_test::static_var;
要不要給初始值沒什麼關係,但這行指明:static_test中有一個static_var,不寫這行編譯時會出現undefined reference to static_var。 取用static物件時,也要用'::'指明:我要取用static_test的物件,例如:
cout << static_test::static_var << endl;
static_test::static_var = 10;
static function是類似的事情,每一個class都可以取用這個function,但static function裡面,只能用到static的member,因為它並非任何一個object的function,自然不能取用其中的內容,就如文中的output()不能取用 i 這個變數。
據說static member最常用的地方是統計目前程式中生成了幾個object,在contructor中對static member+1,destruct的時候-1,不過作者到目前還是沒遇到相關的場合,所以…就算了吧,能用就好。

 4. 致謝: 

本篇文章,感謝陳仕勳(GodGodMouse)強者的指導。

2012年10月29日 星期一

autoEM project: 系列二:option parser

最近因為寫autoEM用到的了python optparse函數,就把相關用法整理了一下。
另外之前看一個BASH譔寫的圖形處理程式(接近700行的code就能完成許多驚人的功能,真的有一點點誇張),也發現到原來BASH內就有內建getopts的功能,雖然說查了manpage發現: All parsing is done by the GNU getopt(3) routines,根本就是直接用C的getopt來做的嘛…
不過getopt在寫大型程式時常用到,就整理一下 C、BASH跟python optparse函數,讓自己不要忘掉,也給大家作個參考:

1. C:
在c裡面用的是unistd.h的getopt,這個方式不接受--XD之類的寫法,getopt_long有提供相關功能,用法還滿相似的,就給大家自己去研究:
getopt(argc, argv, optstring) 並有四個外部變數
extern char* optarg
extern int optind, opterr, optopt optstring
為指定getopt要辨識的參數,大略上有3條規則:
1. 在其中的character,都是合法的參數選項。
2. 後面有“:”的character,需要有後面附加的參數,如-f filename,getopt會將optarg指向該串文字。
3. 加上”::”的character,可以用直接連接的方式加上長參數,如 -oargument,此時optarg會指向argument,但使用者忘記寫argument的話,optarg會指向空字串。
getopt每parse一個參數,就會回傳parse到的參數到opt,如果掃完了,就會回傳-1;遇到不合法的參數,會回傳?;加上:的參數卻沒有在之後寫上對應的參數,則回傳?,如果在optstring第一個字元是:,則上述無參數的狀況會回傳:。

看不懂對不對,看一下怎麼用就明白了:
while((opt=getopt(argc,argv,":o::e:"))!=-1){
  switch(opt){
    case'o':
    printf("%s\n",optarg);
    break;
  case'e':
    printf("%s\n",optarg);
    break;
  case':':
    printf("didn't specify the argument\n");
    break;
  case'?':
    printf("unknown argument\n");
    break;
 }
}
上面只是在範例,把選項輸出一下,實際上要做什麼就做什麼,那其實BASH的情況下是幾乎一樣的寫法:
while getopts o:e: OPTION
do
  case $OPTION in
    o)
      …
    e)
      …
    ?)
      …
  esac
done

2. python的部分:
python下有兩個可行的方法 optparse或argparse,不過optparse好像不再支援,以aptparse為主體。
因為我2.7用的還是optparse,之後有空再來整理aptparse,應該不會差太多…吧?
1. 首先是引入optparse:
from optparse import OptionParser make_option
parser = OptionParser(usage = 'Usage: autoEM [OPTION...] PAGE...',
 option_list=option_list)
usage的部分會自動出現在./program -h時的第一行,同時python會自動將現在的option 2. 定義options: 有兩種方法定義options,一種是呼叫parser
parser.add_option('-v', '--version', action='store_true', dest='version', default=False, help='show version information')
另一種個人比較喜歡,先用make_option把選項都寫在一個set option_list 裡
option_list = [ 
    make_option('-v', '--version', action='store_true', dest='version', default=False, help='show version information') ] 
然後如上面paser = OptionParser的地方,用option_list=option_list把選項一口氣寫進去。

上面這個option,會接下的選項為:
-v foo
-vfoo
--version foo
--version=foo store
會設定options.X的值,X依序為dest ->長參數(version) → 短參數(v)如果前一個沒有給定的話,例如上面會設定options.version。
後面的參數可以加上type=int, float,不設的話store會以string的方式儲存。
另外有store_true, store_false,此時會將dest設為true或false。

3. 處理options:
呼叫parser_args處理argument,default會使用sys.argv[1:]作為參數,當然我們傳自己設定的argument。
options, args = parser.parse_args() args會儲存parse到多少個options。
接著就可以透過options.X的方式,一一寫下各自的處理方式,例如:
if options.filename:
 filename=options.filename
一般來說如果使用者忘了傳入特定參數,如-f忘了寫檔名,optparse都會自動輸出上面的usage,跟相關的錯誤訊息。如果我們要自行呼叫error,可以用parser.error()呼叫,如:
if options.a and options.b:
    parser.error('-a and -b can exist together')
另外optparse還有不少功能,不過上面的對於一般程式來說應該相當夠用了,剩下的就請大家自己去研究了。

3. 參考資料:
1. C的部分:
Linux manpage:
man 1 getopt for BASH
man 3 getopt for C
beginning linux programming 4/e
2.Python部分:
http://docs.python.org/library/optparse.html

2012年10月25日 星期四

autoEM project: 系列一:ssh遠端指令

實際開始做電路之後,遇到很多不太乾淨的東西,跑em算是其中的一個。
跑em中文曰電磁模擬,將電路的實體架構畫出來,去解出其中電磁的實際分佈狀況;這通常要用到大量的電腦資源,在自己電腦上跑會把你資源佔光幾小時,連東方或minecraft都不能打,這當然是無法接受的,這時就要上工作站跑。
而上工作站跑EM就是十足髒髒的事情,大略描述為:
1. 在本地端畫好電磁模擬檔
2. 利用filezilla, scp等把檔案丟上工作站 ,找到你的模擬檔,還要看哪個工作站還在正常運作,不然連一連斷線就GG了。
3. 利用ssh連上工作站,刪除上次的模擬資料,跑模擬
4. 等模擬結束,這時候還不能斷線(這個問題可以用nohup, screen去解決)
5. 用filezilla下載模擬結果,還要再事模擬結果放到原資料夾
整個過程就髒髒的…(這個詞是從BonoGod那邊學來的),最近受到柏翰學長的啟發,決定來寫一個可以自動管理這個流程的小程式,用Shell script譔寫,之後再改用python的譔寫。

程式功能與目標:
1. 免去手動上傳檔案與上工作站執行指令,在本地程式下達upload, run, download指令即可。
2. 支援一次批次大量模擬,自動監視各工作站的使用量,選擇負擔最低的工作站上傳。
3. 監視進行中的模擬,在結束時發出通知。

為這個小程式遇到不少值得記錄的東西,就把它寫一個系列文,這是第一篇,記錄shell 和python上,透過ssh執行指令的各種方式。

1. shell script:

上傳檔案的部分我一開始是選用rsync的方式,使用方式:
rsync -av -e ssh user@hostname:path
後來發現rsync要求兩邊都要有rsync,而工作站上沒有安裝rsync…orz。
所以還是要回去用scp,其實功能不算差很多:
scp file user@server:file //upload
scp file user@server:file //download

下指令的部分則是使用:
ssh user@hostname 'instruction'
這樣的問題是每一次指令都需要使用者輸入密碼,加上上傳下載檔案,跑一趟em都要使用者輸入3次密碼,這樣還是很沒效率。
解法方式是設定ssh公鑰,或者用類似expect的方式來模擬使用者輸入。我是用前者的作法,在code裡加上一個add worstation 的指令,自動產生公鑰並上傳到指定的工作站上,之後即不會要求每次執行都要輸入密碼,這部分詳述資料請見參考資料一。

另外如何在ssh被切斷之後,執行的程序還能繼續?
這部分有滿多解決方案的,最簡單的是用ssh本身就有的功能:
ssh -f user@hostname 'instruction'
這樣指令就會自動在遠端背景執行。
或者如柏翰學長使用的方式,用at來執行:
echo "em -v $file > em.log 2>&1 &" > sub_file
at now +$delay minutes < sub_file
或者就要透過nohup或是screen/tmux兩種方式:
ssh user@hostname 'nohup instruction &'
ssh user@hostname 'screen -S autoEM -d -m instruction'
這兩個方式略有不同,nohup會讓程式忽略所有SIGHUP(hangup)的信號,ssh登出時的hangup信號就不會把該指令給刪除。
Screen則是直接創造一個virtual console(其實我也不確定是不是這樣叫orz),-d -m會detach這個screen,指令就在裡面繼續跑,之後再用screen -r將程式給要回來;不過又發現有工作站上沒有screen或tmux(......),如果遇到這個問題,可能就真的只能跟管理員反映了...。

2. python:

如果改成用python來寫呢?
Python裡已經有SSH2 protocal的套件庫paramiko,比較可惜的是這個套件目前載不到python3 的版本,只能先用2.7寫。
Python 寫起來就直覺多了,paramiko已經把大部分ftp的指令都整合在套件庫裡,包括sftp跟ssh,document頁面在:http://www.lag.net/paramiko/
大家可以載一下它們的安裝檔,裡面的demo.py就有很多範例可以用,包括sftp, ssh:
ssh = paramiko.SSHClient()  
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
ssh.connect(info.hostname, username=info.username, password = info.password)  
stdin, stdout, stderr = ssh.exec_command('source ~/.bashrc; nohup em ~/autoEM/%s em.log 2>&1 &' % filename)  
stdout.readlines() 
stderr.readlines()
因為paramiko已經把ssh包在裡面,我沒辦法像shell一樣,用ssh -f的方式去下背景指令,因此就用nohup的方式;比較有趣的是,指令中,我一定要重導向輸入跟標準/錯誤輸出(不能讓nohup自行產生nohup.out),在下完指令後也一定要stderr.readlines(),否則我ssh切斷之後nohup還是會被切掉,這部分原因不明。

3. 小結:

這篇主要記錄如何透過ssh,在BASH, python上對遠端工作站下達指令,目前這部分已經完成,下一篇可能會談一下主程式譔寫時遇到的問題,或中途寫下的筆記。

4. 參考資料:

1. 鳥哥的網頁,有關ssh的部分:
http://linux.vbird.org/linux_server/0310telnetssh.php
2. python paramiko package:
http://www.lag.net/paramiko/

5. 致謝:

本篇文章感謝:
陳柏翰學長在自動執行EM的shell script上的分享。
黃偉寧前輩在nohup, screen程式譔寫上的指導,雖然在討論過程中,前輩提供了無數種解決方案,模擬使用者行為,其他指令等,但我最後都沒有用上Orz(應該說…有聽沒有懂,我們之間至少差了20dB左右)。

2012年10月17日 星期三

archlinux下使用jnc連接學校VPN

從學校的宿舍搬出來後,為了要從學術資料庫裡載paper下來看,對VPN連線的需求日益孔急,一時之間找不到連線辦法,只好使出最智障的方式:在Vbox裡面開windows然後從windows裡面連VPN…。 但這個方法實在太腦包了,最近經過一番嘗試,總算成功在Archlinux下連接學校VPN,在這裡記錄一下解法的各步驟:

1.程式配置: 安裝jnc,這個簡單從AUR裝就OK惹
https://aur.archlinux.org/packages.php?K=jnc&SeB=x
從學校VPN載到juniper client的檔案,學校已經壓成rpm檔,於是用rpmextract.sh解開它,裡面有幾個程式包括:NC.jar, ncsvc, libncui.so之類的
把解壓縮的檔案放到~/.juniper_networks/network_connect裡面

2.修改jnc: jnc的執行程式是用perl寫的,位置應該會裝在/usr/bin/內,用超級使用者權限做一些修改:
my $ncdir = "$ENV{'HOME'}/.juniper_networks/network_connect";
my $configdir = "$ncdir/config";
這兩個指定VPN執行檔與設定檔的的位置,覺得這兩個地方風水不好的話,可以修改這個地方。
my $gui = 1;
可以設定要不要有gui介面,這部分需要java,我懶得管什麼gui就把它改成0 XD

3.設定檔: 如上,預設的設定檔為~/.juniper_networks/network_connect/config/default.conf
格式如下:
host=foo.bar.com
user=username
password=secret
realm=very long realm with spaces
cafile=/etc/ssl/bar-chain.pem
certfile=
下面則是我的設定檔,為了保護學校的校譽,在這裡把學校名字蓋住:
host=sslvpn.XXX.edu.tw
user=garbage
password="Garbagepass"
realm=XXX Email Account
cafile=/home/yodalee/.juniper_networks/network_connect/XXX.pem
certfile=
在realm的部分,就是登入vpn時除了帳號密碼外的那欄,我是用chromium F12看原始碼找到相對應的地方
<select size="1" name="realm">
注意這裡大小寫要全對才會過。

4.VPN認證檔: 這地方要從VPN提供者的網頁載下它的認證,使用下面的指令:
openssl s_client -connect url:443 > test.pem
然從編輯該pem檔,把-----BEGIN CERTIFICATE-----到 -----END CERTIFICATE-----以外的部分都刪掉,把這個pem檔放在設定檔中,cafile指定的位置

5.特殊權限: 這部分主要是參考資料2中所提到的: 好像是因為jnc呼叫的ncsvc中,會更動/etc/resolve.conf的內容還是怎麼樣,要對ncsvc的權限做特別設定,我也沒有試著不設定然後連結VPN,不知道不設會怎麼樣:
$ sudo chown root:root ~/.juniper_networks/network_connect/ncsvc
$ sudo chmod 6711 ~/.juniper_networks/network_connect/ncsvc
$ chmod 744 ~/.juniper_networks/network_connect/ncdiag 

6.連結vpn: 使用jnc就可以直接連結惹 沒圖沒真相,用vpn連結學校資料庫,可以看得到只有學校網域才享有的download full text:

再用jnc stop就可以切斷vpn連線。

參考資料:
1. https://wiki.archlinux.org/index.php/Juniper_VPN
2. http://www.rz.uni-karlsruhe.de/~iwr91/juniper/

致謝: 本篇文章感謝黃偉寧(AZ Huang)同學的指導

2012年10月5日 星期五

傳輸線穩態解與暫態解



這幾天在讀電磁學,發現一個自己沒想過,卻滿基本的問題:
我們先拿一個最芭樂的傳輸線模型,如下所示:
現在假設Vg=1VZs = 50ΩZ0=50ΩZL=25Ω,線長λ/4(懶…選個簡單一點的數字)
請問從傳輸線入射的功率為?

解法一:
Zs和傳輸線的交點分壓
P = ½ * ( 1 * 50/(50+50) )^2 / 50 = 2.5mW
解法二:
25Ω經過傳輸線得到Zin = 100Ω,與Zs=50Ω分壓去解,得到2.222mW

問題:為什麼兩個答案是不一樣的?

--

答案:
兩個解法其實是在不同的條件下去解的。
在第一個解法時,我們看的是輸入的電壓在遇到兩個不同的介面時,電壓的分佈狀況。
第二個解法時,我們是把整個傳輸線和load,等效成一個電阻,去計算功率的分配。
不一樣在哪?
在解法二裡面,我們省略了傳輸線用電阻等效時,已經把電磁波經過不同介面的反射穿透都考慮進去,看看多少的功率被傳到傳輸線和load端(因為傳輸線為無損耗,所以就是在算load消耗的功率);但在解法一,我們只考慮了瞬時的功率分配,後面的效應還沒有考慮。

我們可以把解法一繼續解下去。
V=1/2, ΓL = -1/3,在輸入端無反紙,功率消耗在Zs上,反射功率為(1/6)^2 /2/50 = 0.278mW
所以Vg從傳輸線打入2.5mW,反射回來0.278mW,在傳輸線(或load)上消耗的功率為:
2.5-0.278 = 2.22mW
解法二實際上是在解整個電路的穩態解,解法一只是電路打開一瞬間,在Zs和傳輸線上的暫態。

所以說,哪個是真的?
在現今的電路模擬中多是利用頻域模擬,將一塊電路變成某個S參數、Z參數…的陣列,所做就是將電路的延遲效應給排除,只看電路在穩態下的特性,也就是解法二所做的事情。
但課本中的圖形,有正反向電壓波反彈反彈直到穩態解的,就需要第一種解法才能表示。

--

第二個是同樣概念的問題:
同樣是上面那張圖,現在Zs=50Ω, Z0=25Ω, ZL=50Ω,線長λ/4(懶…一樣選個簡單一點的數字)
input端的反射係數:
解法一:先算ΓL=1/3經過λ/4線後,Γin=-1/3
解法二:Zin = 25^2/50 = 12.5,得到Γin = (12.5-50)/(12.5+50) = -3/5
問題:為什麼兩個結果不一樣,哪一個是真的?

同樣,第一個解法只是考慮在load端的一個暫態下,每個入射的電壓波會有多少反射;但我問到Γin時,就是要把整個電路等效成一個阻抗,然後看看入射的電壓波有多少會反射。
這時,因為ZsZ0的不匹配,從ZL看到的阻抗其實不是25Ω,而是12.5Ω,算到Γ=3/5,再經過了λ/4的傳輸線,可得到輸入處的反射係數為-3/5

結論:
一般微波電路在討論時,是針對穩態解的參數如Z, S matrix下去討論的,這樣的結果和只討論暫態的結果當然不一樣,計算時要稍微注意。

2012年9月30日 星期日

程式上色

其實這是整理在BBS上的舊文,想說就把它轉到這裡來,是記錄如何在程式裡面加上顏色的控制,如果熟BBS的人應該很熟悉,似乎是一個公訂的標準上色方式,大家參考參考,也許可以讓你的程式增添不少色彩,能不能為人生上色就說不準了。

1. ANSI C:
開始上色格式:\033[x;y;zm
結束上色格式:\033[0m //其實就是設定為無屬性
\033就是escape字元,可以用\e來代替
x,y,z三數字分別定義字型格式、前景、背景。

x:
0 無屬性
1 明亮字體
2 暗淡字體
4 底線字體
7 反白字體
8 匿蹤字體 

y,z:
30~37 為字體顏色 黑紅綠黃藍紫青白
40~47 為背景顏色 黑紅綠黃藍紫青白

ex: printf("\033[1;33mtest\033[0m")
ex: printf("\e[1;33mtest\e[0m")

2. BASH shell:
第一種方法,可以用printf來實作,這和C就是一樣的了
至於echo,要用echo -e的方式,讓它解讀escape跳脫 ,之後的寫法也一模一樣。
值得一提的,這個設定對bash prompt也有用,比如說我的PS1參數的設定: [\e[1;32m\u\e[0m@\e[1;34m\h\e[0m \e[1;33m\W\e[0m]\$
很難看懂,總之,綠色的使用者名稱,藍色的電腦名稱跟黃色的路徑,還滿潮的XD

3. curses.h 雖然說現在用curses.h的程式好像滿少了,不過就寫一下吧,主要有五個步驟,那時候在ubuntu上測試是OK,還寫了一些東西,這次把它拿出來看發現已經看不懂了Orz。
    一、利用has_color() 偵測是否有顏色支援
    二、start_color() 開啟顏色支援
    三、init_pair(pair,f,b) 設定屬性
    四、attrset(COLOR_PAIR(pair)) 設定接下來使用這個屬性來輸出
    五、attroff(COLOR_PAIR(pair)) 關掉這個屬性
第三部的init_pair裡:
pair指的是要存在第幾個顏色設定暫存中 可以指定1~COLOR_PAIRS這麼多組,可以用printf("%d",COLOR_PAIRS)來得知,ubuntu10.10終端是64組。
f 指字體顏色,b 指背景顏色 可以用數字,也可以用在curses.h中定義好的代碼
COLOR_BLACK    0
COLOR_RED 1
COLOR_YELLOW 2
COLOR_GREEN 3
COLOR_BLUE 4
COLOR_MAGENTA 5
COLOR_CYAN 6
COLOR_WHITE 7
其實順序跟就跟之前提的一模一樣…
屬性的部分,也有預先定義好的可以使用,ex直接attrset(A_BOLD即可),不同的屬性可以用 | 來加總,不過也別加太多= =。
A_NORMAL 正常
A_STANDOUT 些許高亮度
A_UNDERLINE 底線
A_REVERSE 反白
A_BLINK 閃鑠
A_DIM 暗淡
A_BOLD 粗體
A_PROTECT 沒試過…不清楚
A_INVIS 匿蹤
A_ALTCHARSET 沒試過…不清楚
A_CHARTEXT 沒試過…不清楚

4. 參考資料:
基本上色:
https://wiki.archlinux.org/index.php/Color_Bash_Prompt
其餘關於ncurses:
http://doc.linuxpk.com/55549.html
http://fanqiang.chinaunix.net/a4/b2/20020626/060200258.html
http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/

5. 結論: 顏色上色固然漂亮,可是也會讓輸出的內容變得較難閱讀,請不要太頻繁的使用。

2012年9月27日 星期四

C++ template使用注意事項

這篇是對上一篇python-like cpp譔寫過程中,遇到的一個疑問。
主因是我在寫一個含有template的Array class,雖然說內容是抄別人的,可是個人自作聰明做了些小修改,結果編譯怎麼樣就是不會過,後來才在google上找到解法,在這裡記錄一下。 我查到最完整的回答是:
http://stackoverflow.com/questions/8752837/undefined-reference-to-template-class-constructor
看到有人的評論是:This has been answered a million times.。我也知道這個問題對比我厲害一點的人都是常識了,可能N年前修資料結構甚至程式設計的時候就被表過了,不過我倒是第一次遇到,大概是從來沒好好的寫過程式吧。
以下就整理一下問題的相關背景、發生原因和解決方式,主要都參考上面的回答。

1. 問題背景:
程式架構其實相當的芭樂,自定義的class Array:Array.h, Array.cpp,記錄一個template類型的動態陣列,會在初始化時排定空間,透過get和set 對其中的元素取值或賦值。
當我在main裡面使用Array a(10),然後將main.cpp, Array.cpp一同編譯時,就出現了下列的錯誤訊息:
main.cpp:(.text+0x1d): undefined reference to `Array::Array(int)'
main.cpp:(.text+0x3d): undefined reference to `Array::set(int const&, int&)'
main.cpp:(.text+0x6f): undefined reference to `Array::get(int const&)'
main.cpp:(.text+0xb8): undefined reference to `Array::get(int const&)'
main.cpp:(.text+0xd8): undefined reference to `Array::~Array()'
main.cpp:(.text+0x183): undefined reference to `Array::~Array()'
總之一切定義、用到的function都找不到。

2. 問題原因:
我們可以把class分為三個階段:Array.h檔內宣告、Array.cpp檔內定義、main.cpp內使用。 這個問題的原因在於,gcc在編譯時並不會同時編譯所有檔案,而是將檔案視為獨立,最後透過linker將上述的檔案連結在一些,消除其中的reference。
template只是一個標註,告訴compiler這個型別還未定型並可置換,當指定如何使用時,才會解開置換並編譯相關的原始碼,compiler在處理Array.cpp時,完全不會編譯Array<int>, Array<float>…等class,除非如下文所示,利用強制的方式指定編譯某個型態;處理main.cpp時,gcc的確在Array.h裡面看到Array的宣告式,因此它將Array的function設為reference,讓linker去尋找相對應的執行碼。
最後linker要連結時就發生問題了,main.cpp要求Array的code,但在Array.cpp裡面卻沒有,就成了undefined reference。

3. 解決方法:
這個問題有三個可行的解決方法:
第一是不要像我一樣傻傻的把class分成兩個檔案,而是直接將宣告和定義寫在相同的.h裡,如此一來,編譯main.cpp時遇到Array即可在Array.h裡面找到對應的template code並編譯。
第二種解決方法,是在Array.cpp的檔案末端,明確的告訴編譯器,這裡有哪些型別的class需要編譯:
template class Array;
template class Array;
… 
產生的Array.o內部,就有Array編譯完成的code供連結。
第三種方法是直接在使用的地方#include Array.cpp

三種方法各有優劣。
第一種方法容易加大原始碼的大小,並把定義和宣告寫在同一個檔案內,也會增加編譯時的成本。
第二種方法的彈性較低,寫了哪些就只能用哪些,對於大多數的STL物件或許還OK,如果程式中有自定義的class就成了大問題;現今STL為了支援泛型,都是用第一種方法來譔寫。
第三種方法當然也OK,但其實跟第一種方法沒什麼兩樣,甚至還會增加引入時的複雜度和錯誤的可能性。

4. 結論:
template算是泛型程式的基礎,讓程式碼可以依據使用者的需求,編譯出不同的執行檔。 也因此,在使用template時,程式的宣告和定義無法分離於不同的檔案。
一般來說,採用將宣告與定義放在同一個檔案內是基本的做法,可以保有未來的擴增性;如果這份程式只是自己的project內要使用,確定只支援哪些類型,就可以分離兩部分,並明確指明編譯哪些類型。

5. 致謝: 本文內容感謝黃偉寧(AZ Huang)同學指點,感謝諸位的觀看

2012年9月26日 星期三

C++ python-like debug message


在C++下,如果程式寫得大一點,又有自己寫的資料結構、繼承、多型之類的,如果有地方寫錯了,這時debug起來通常相當麻煩;過去筆者都是用gdb跑到當掉的地方,再用backtrace幾次,看看是哪裡出了問題,可是這樣還是有點麻煩;又次用到srilm等套件,backtrace 10次還是不知道錯在哪...
最近跟柏翰學長學到一個debug的技巧(雖然說學長表示他也是跟別人學的),可以在C++上實現python-like的錯誤訊息,很清楚的就能知道錯誤是在哪發生的,在這裡把這個方法整理一下,分享給大家。

1. python-like debug message:
python的debug訊息好處在於,在一個function中出錯,它會有自動traceback的功能,一路把呼叫該錯誤部位的function一路吐出來:
例如一系列函數呼叫如下:err1()->err2()->err3(),然後在err3裡raise一個error,console會輸出
Traceback (most recent call last):
  File "./error.py", line 17, in <module>
    err1()
  File "./error.py", line 14, in err1
    err2()
  File "./error.py", line 11, in err2
    raise(KeyError)
KeyError
其印出的格式整理如下,含$為變數:
File $filename, line $lineno, in $functionname
error code

2. C++ exception:
C++ 提供了try, throw, catch來進行例外的處理機制,相關文件請眾位參考網路上的其他資源,例如:
http://caterpillar.onlyfun.net/Gossip/CppGossip/ClassTemplate.html
這裡只簡單帶過,簡而言之,在try裡造成發生錯誤的情況,throw出一個錯誤,由catch端決定如何處理。
我們利用這樣的處理機制,遇到出現錯誤的狀況,例如提取不存在的資料時,直接throw出一個錯誤,並利用全域的catch(...)將它接下來,利用compiler的內定巨集__FILE__, __LINE__可以編寫出適當的錯誤訊息;同時,可以在catch中再throw一次,將錯誤再往上一層函數丟,如此一來就能達到function traceback的功能,整體程式碼的架構如下:
function err1(parameter)  //throw error function
{
#ifndef NDEBUG
 try{
#endif
 /* code */
#ifndef NDEBUG
 } catch(...) {
 cout << "Traceback:\n";
 cout << "File: " << __FILE__ << ", line "<< __LINE__ << ", in " << __func__ << endl;
 throw; 
 }
#endif
}
利用#ifndef NDEBUG,可以快速重新編譯沒有這些debug訊息的發行版。
利用巨集,則可以讓程式碼看起來更簡潔一點
#define STARTEXCEPTION try{
#define ENDEXCEPTION \
 } catch(...) {\
 cout << "Traceback:\n";\
 cout << "File: " << __FILE__ << ", line "<< __LINE__ << ", in " << __func__ << endl;\
 throw; \
 }

function err1(parameter)  //throw error function
{
#ifndef NDEBUG
STARTEXCEPTION
#endif
 /* code */
#ifndef NDEBUG
ENDEXCEPTION
#endif
}

3. 範例:
我試著提出一個小小的範例,我們現在寫一個Array的object,可以在宣告時指定大小,get 和set 其中的內容(好吧我承認這個code其實就是cv上面連結來的,不過在template的class時我遇到一個template的問題,透過google大神解決了,之後再來寫一篇。)
在get和set的地方,原本都會去檢查index有沒有在範圍之中,否則會存取不存在的值,那我們現在在code中加上上述的exception,下文中,粗體為加入的部分。
template<class CType>
CType Array<CType>::get(const int &i)
{
#ifndef NDEBUG
STARTEXCEPTION
#endif
 if (isSafe(i)) {
  return _Array[i];
 } else {
  cout << "Index out of range\n";
  throw 1;
 }
#ifndef NDEBUG
ENDEXCEPTION
#endif
}
在main裡面,當然也要對呼叫function的地方加上STARTEXCEPTION跟ENDEXCEPTION,當我試圖get超範圍的值時,就會出現錯誤。
Index out of range
Traceback:
File: array.h, line 59, in get
Traceback:
File: main.cpp, line 31, in main
terminate()
我認為,這個方法雖然提供了明確問題的發生途徑,但仍有下列三個問題:
正常的exception做法,應該會去自定義exception handling的class對exception進行處理,才能真正的避免問題,如記憶體漏失;這個方法只是要讓程式終結,輸出較明確的錯誤訊息,而非解決該excetion的發生。
另外,function中使用的__LINE__的行數是大略值,__func__的巨集好像也還沒統一,隨不同家的編譯器也會有不同的定義:
http://stackoverflow.com/questions/2192680/macro-keyword-which-can-be-used-to-print-out-method-name
最後,這個方法深入所有的function,這在程式用到大量函式庫的狀況下,把每個function加上這個code的代價相當昂貴。

4. 如何佈署?
還有另一個問題是,要如何將這些內容佈署到code當中?
在這裡有兩個不同的方式:
第一種是學長所用,取代"^{","^}"為STARTEXCEPTION和ENDEXCEPTION,這個方法極度要求格式的一致,function的括號一定要在行首,像我code格式都亂七八糟的人就不適合。
第二種是用vim的snipmate,定義STARTEXCEPTION和ENDEXCEPTION的pattern ,在指定的地方插入,搜尋時可以利用vim plugin: taglist,可以幫你列出所有的function,並支援快速跳到function 的所在地。

其實我認為應該還有更好的方法,或許是利用cscope或ctags來parse出所有function 的所在地,自動或詢問要不要加上debug訊息,不過目前還沒找到這樣的方法。

5. 結論:
本方法利用C++的exception, throw的功能和g++的MACRO,實現python-like的錯誤訊息,可以有效加速C++複雜程式上的debug過程;利用vim的自定義巨集,我們可以自動在所有函數加入此功能,並用ifndef NDEBUG guard的方式,確保未來可輕易在發行版中移除此功能。
但另一方面,此方法其實無法解決問題,僅是幫助指出問題所在對終止程式,真正防止程式出錯或記憶體管理還是要靠完整的exception handling。

6. 致謝:
此文章感謝柏翰學長的指導
並感謝眾位的觀看,不好意思浪費了大家的時間。

2012年9月22日 星期六

我的vim設定

最近梗比較少,寫不出什麼有用的東西
整理了一下自己的vim設定,就把自己的設定跟plugin分享一下好了

1. plugin
裝的plugin主要有幾個:
autoComlPop: 輔助omnicomplete的文件單字補齊
http://www.vim.org/scripts/script.php?script_id=1879
LargeFile: 開大檔用,其實比較少用到
http://www.vim.org/scripts/script.php?script_id=1506
surround: 快速修改相對應的標籤
http://www.vim.org/scripts/script.php?script_id=1697
NERDtree: 快速瀏覽目錄
http://www.vim.org/scripts/script.php?script_id=1658
snipMate: 自訂關鍵字補齊功能,缺點是會變笨
http://www.vim.org/scripts/script.php?script_id=2540
taglist: 程式碼概略瀏覽
http://www.vim.org/scripts/script.php?script_id=273

附帶一提,這些plugins全部都裝在~/.vim裡面
我發現可以用dropbox,建一個setting的資料夾
把.vim sync到dropbox上,這樣以後重裝電腦
只要把這個資料夾再複製回來,這些plugin就都裝好了

2. vimrc
我的vimrc如下:
paste.plurk.com/show/1313103
一開始是編碼和layout的設定,然後是各個plugin的設定
用F12可以開taglist
用F7可以用當前的makefile進行make
之後可以用F8列出quickfix所有的錯誤編譯訊息
Ctrl+n Ctrl+p在錯誤內容進行跳躍

omnicomplete的部分是針對各種檔案格式,去設定omnifunc要用哪一種
比較奇怪的是,在vim73上面,omnicomplete的功能被嚴重限縮了
目前還不知道原因Orz

最後就是一些filetype的link
比如說把php, html的filegype交互設定,這樣在php檔裡面也可以使用html 的snipMate快速補齊;cuda 和lex也是相同的道理
3. 結論
這是一篇廢文
其實vim功能相當的強大,能安裝的plugin也多的很
這個設定只是分享,使用習慣還是大家平時用習慣最重要

2012年8月30日 星期四

翻譯:the free lunch is over

http://www.gotw.ca/publications/concurrency-ddj.ht m
好文共享,硬體的極限與未來軟體的挑戰
其實這是一篇有點老的文章(2009),想說就提個大概內容,加一些個人的解釋,分享一下。

--

CPU已經來到極限了,我們曾經在摩爾定律下,每18個月把transistor的數量加一倍,享用更快的處理速度,更佳的效能;很可惜的,硬體效能增加的同時,我們的軟體也進一步吃光所有多出來的效能,更多的供給推出更大的需求,以前我們只要計算機幫我們算答案,現在我們卻要手機和我們對話。

硬體製造商急於推出更快的產品,在各種方法上用盡心力。

但在三個推動CPU加速的關鍵:clock speed, execution optimization, cache,都遇到各自的問題。

首先是clock speed:
clock是數位晶片的心臟(或說動力,你要說查克拉也可以),每一個運算單元靠clock來同步資料的寫入、運算和輸出,理論上,加速clock等效於運算速度的加倍。

但這有極限。

半導體靠的是電位的高與低來表示數位的1與0,每進行一次轉換,都會對電容進行一次充電或放電,clock愈快,充放電的頻率也會更快,相對的就是功耗的提升,理論上,這個功耗和clock的頻率是平方的關係,現在高效CPU的功耗大概都在100W~200W間,這大概跟一台冰箱差不多,這些熱會在大概2~3 cm^2的面積內的產生,通過各種散熱膏、散熱片、風扇帶到晶片外,所以上youtube 查查'cpu cooking' ,你可以找到用CPU烤肉、煎蛋的影片。
http://www.youtube.com/watch?v=7uBNCN6v_gk

甚至還有對記憶體超頻結果把封裝燒掉的影片……
http://www.youtube.com/watch?NR=1&feature=fvwp&v=Gw-rUCwLoQ0

也可以知道…為什麼現在瘋狂的超頻者,甚至要用液態氮來冷卻CPU。
http://www.youtube.com/watch?v=tPzNl1t4Qmk

當然…個人PC大概還不會出現水冷式的系統,目前clock 頻率的上限,大約就在3.6~3.8GHz左右,再上廢熱會超過氣冷式的極限。

另一方面execution optimization希望能在每個cycle中執行更多的instruction,無論是pipeline, branch prediction等等,這裡面有相當複雜、有關硬體設計的思維,但同樣的,能從execution optimization 中榨出的效能也面臨極限,甚至出現過processor會調動write, read的執行序列,以換到更多效能…。
加上更多的cache也是個不錯的方法,以前,記憶體和CPU的速度是相同的,雙方合作良好;後來CPU的運作頻率遠遠超過了記憶體,於是出現了cache來保存CPU運作中需要的資料,CPU得以進行更快的運算。

當上述方法都來到了極限,目前主流都超向另一個方式;利用hyperthreading(超執行緒?), multicore(多核心)的方式來換到更多的速度,這兩種方法其實都不是運算速度的增加,而是用面積來換到一些速度,就像生產線滿載了,就要蓋一家新工廠。
Hyperthrading的作法是複製一些記錄CPU運算狀態的單元,並不包含關鍵的ALU的運算單元,這讓作業系統可以「看到」兩個運算的單元,當其中一個運算單元閒置時(許在等cache或memory的回應),另一個運算單元就可以取用關鍵的運算單元執行運算,就像靈夢休息的時候,魔理沙就會出來接手。

這詳細的可能還是要問晶片設計組的同學們orz。
Hyperthreading需要有作業系統的配合,增加大概5%的面積,可以換到5~15%的效能提升。

multicore就不較沒那麼稀奇,直接複製一套core,讓作業系統去分配,但更多的core絕非效能等比例上升的意思,不是每一個運算都能夠平行的處理,指令間需要shared data時也會加深系統的複雜度。
面對多執行緒和多核心的趨勢,本文作者認為concurrency(多工?同步?)將會是未來軟體的重大變革,未來的程式會在多核心上運行,要如何避免多工上的deadlock和各式新型態的錯誤,事實上我認為這早已是現代進行式,否則我們不會有那麼多多核心的電腦正在運行。

作者在此提出幾點結論:
1.未來軟體設計要能了解何類工作可以平行化處理以加速,哪些不行,並能譔寫相對應的程式。
2.CPU火力無限的時代已經結束了,以前程式速度卡在網路、記憶體、database,這些東西還在進步當中- TLE, SSD... - 但CPU大概已經到了極限,短時間內看不到突破性的可能。
3.承上一點,軟體的optimization將會愈來愈吃重,Vista轉換到win7證明了軟體optimization可以有多大的效能進步,未來軟體將更需要這些。
4.programming language也要面對concurrency的問題,例如,雖然大多數的大型程式以C++為核心,但C++並未將concurrency納入考量,因而需要限於平台的library來處理concurrency的問題;一套統一concurrency問題的標準也亟待發展。

Reference:
Wikipedia about hyperthreading:
http://en.wikipedia.org/wiki/Hyper-threading
CPU power consumption comparison:
http://www.tomshardware.com/reviews/ivy-bridge-benchmark-core-i7-3770k,3181-23.html

2012年8月20日 星期一

不正經,開箱文

最近因為筆電快要解體,不開玩笑,像正面偵測螢幕的按鈕竟然掉下來了。

就趁著八月台北資訊展時入手一台,因為平常要跑很多模擬的程式,需要的是運算力強的機種,本人又是個效能控XD,也不想盯著太小的螢幕,經過綜合評估,最後入手的是這台ACER Aspire V3-571G,近日解禁,於是來寫個不正經的開箱文:

官方網頁:
http://www.acer.com.tw/ac/zh/TW/content/model/NX.RZNTA.002
算是這個系列的頂級機種了,買價是30.8k,pchome上是賣33.4k,差別在pchome有送Dialog3,但那個東西對我價值是0元,如果有送minecraft 帳號或是東方全套我倒是可以考慮一下。

CPU:i7-3610QM,記憶體加到8G,整體而言不重,加上電池2.2kg,比我舊的Aspire 5633還要輕。這裡真的很想表一下…電池可以拆我是很高興啦,但你好歹設計一個備用電池,當我主電池拆下來,插頭又被拔的時候,可以撐個5分鐘;不要插頭一拔,螢幕就瞬間黑掉。

外觀是所謂「鋼琴烤漆材質」,亮到會發光…,不過也超容易沾指紋,我甚至不用燻強力膠就看得到我的指紋了,所以千萬別拿這台筆電當兇器,光指紋就可以釘死你!

15.6大尺寸的螢幕…毫無反應,就只是個螢幕。


鍵盤是所謂的「巧克力鍵盤」,雖然說我不知道為什麼叫巧克力鍵盤,也不能吃又沒味道,不過打起來還頗順手的,聲音有點大。


使用狀況:
打開電腦,內建有預設的windows7,整體windows跑分有5.9,鎖在硬碟的讀取效率


然後windows再見,再來大概很久不會再見了=w=。

我選的linux是Archlinux x86_64
只看CPU的話,效能超讚,在archlinux下跑linux的pi指令,算到小數點下1000000位,用time來記時,用real來比較:
$time pi 1000000 > /dev/null
舊筆電的Intel(R) Core(TM)2 CPU T5500 1.66GHz要8.5秒;桌電的core 2 quad要5.6秒;這台i7只需要1秒啊!


電池也很強,從晚上7點到12點,全程都在跑archlinux安裝,電池很夠,當然也可能是過程中都沒啟動X。
在archlinux下,因為optimus的關係,顯示卡應該還沒連上,灌的時候X搞了很久,後來只用intel driver才進到X裡,真的超想說
nVidia Fuck You!

其實無線網卡也連不上,broadcom bcm57781的卡,自己編譯驅動還有一些錯誤要修…
不過,只灌了Intel-dri就有了不錯的成績,minecraft視野調到far的fps還有50~60,拿來打東方打起來也很順,附個圖。



另外網路上有說這台打Dialog3的時候會有過熱的問題,個人沒打Dialog3,但就算是安裝時,出來的風也沒有很熱;整體給分我給85/100,推薦給有高運算、高效能需求的人;小扣一些主要是三點:
1. 電池設計:
2. 對linux使用者來說,Optimus真的很崩潰…
3. 這台比較新,無線網卡linux好像還沒有支援到,現在linux處於沒無線網路的狀態。
當然如果你用windows就沒什麼差惹。

2012年8月9日 星期四

正規表示法:規則篇


正規表示式(Regular expression, RE)--規則篇:
正規表示式是個強大的工具,定義了明確的定串比對規則,來幫助使用者把梳字串,在很多程式都有支援,如Linux shell grep, awk, sedvi(m)的搜尋取代功能等,C語言的scanf其實也有支援,可惜正規表示法規則甚多,一時之間難以記全。
這篇主要記錄正規表示法的規則,整理自“Practical Programming in Tcl and Tk”第十一章,給自己做個參考:

  1. 一般字元與跳脫字元:
如果要比對字串,最簡單的規則就是:把字元寫出來,當寫:
a,就會比對出a,夠簡單吧。
但這樣就沒啥變化了,如果我要比對a, aa aaaaa...aa呢?如果全部的東西都是直接比對,就少了這種彈性,所以正規表示式定義下例幾個字元為跳脫字元,平時做為特殊處理之用,要比對他們需要特殊規則,包括:
.*+?()|[]^$\
在比對中寫下這些符號的功能之後會一一介紹到,如果是要比對這些符號,就用backslash \ 跳脫。
例如要比對\,就需要寫\\而非只有\

  1. 字組(character sets)及多重選項(alternation)
如果我們要寫一個讓使用者輸入y/n的程式,使用者可能會填y/Y/n/N裡面一個,因此就有了字組的概念,字組利用跳脫字元[],讓某一個位置有多重選項:
[yY],則yY都可以match
[]裡面可以使用“[x-y]”的規則,來比對某區間的字,例如:
[0-9]比對所有數字, [a-z]比對小寫的英文。
這裡要注意的是,隨著語系的選擇,[x-y]會有不同的範圍,不過一般都是以LANG=C的情況下去設計,也就是0-9A-Za-z的排序。
子規則1:反向用[^],例如我要比對“不是<”,就用[^<],如果是[^a-z],就會排除所有小寫英文。
子規則2:比對跳脫字元除了]需要在[]要排第一位、\仍要跳脫外,其他在[]就不用跳脫,直接寫就可以
例如下行會比對出所有的跳脫字符:
[][.*+?()|\\]
另外則是{}這個直接寫就是直接match,但加上\{,\}後則是跳脫為特殊意思。

  1. 數量(quantifiers)比對與比對順序:
如果像上述,我們要比對a,aaaaaaaaa...aa,或者我們只要使用者輸入「o某字z」,他要orz, otz,omz 我才不管呢?
首先使用的是「.」,這是RE中的「任意一個字元」,跟shell的不太一樣,這要小心。
所以上面的比對,我們可以寫 o.z
那針對不同的數量,我們就需要數量字符:*+? 以及{m,n}
字符
代表數量
*
0~∞
+
1~∞
?
0~1
{m,n}
m~n次,其中n可以不填,表示∞
所以說,上面的比對可以用 a+ 完成。
重複的可以用()包起來,[]裡面的重複也OK,將數量字符直接加在下括號的後面即可。
比較重要的是 * 這個符號用起來要小心,這個比對表示任意字符重複0~n次,有時會造成不預期的結果。這就牽扯到正規表示法的比對規則了,如果一個match在字串中有多個相符的比對時,其規則如下:
  1. 各相符比對,最接近開頭者優先:
  2. 如果是一樣的開頭,預設最長者優先,這個可以改換為nongreedy,即較短者優先。
所以如果用 [a-z]* 去比對 123abc,一般可能會預期取出abc,但不對,在123前的開頭的空字串才是優先match的對象,一般都建議用+強制一定要有match來避免這樣的狀況。

  1. 字集(character classes)
字集為一些設定好的字元組合,寫法為:[:identifier:]
整理可選用的identifier如下:

identifier
比對:
等同表示法:
lower
英文小寫
[a-z]
upper
英文大寫
[A-Z]
alpha
英文字母
[A-Za-z]
digit
數字
[0-9]
xdigit
十六進位數字
[0-9a-fA-F]
alnum/print
以上總集合
[0-9a-zA-Z]
punct
標點符號例如 `'”/<>之類


graph
非控制字符或空白類字符,其實就是以上總集合
我猜可以寫成[[:alnum:][:punct:]]
blank
空白和tab
[ \t]
space
空白類字符:空白,換行,回車,tabvertical tabform feed
有人知道後兩個是蝦毀嗎…
\s
cntrl
控制字符:ASCII 0~31


< >
分別比對單定開頭與結尾



  1. 定位字符(anchoring)
這部分兩個定位就是^$ =w=

  1. 反斜線跳脫:
利用反斜線的跳脫字符,可以match一些特殊的字符,主要分為四類:特殊符號類;與字集相同的設定,可以match一個字集;定位字符類;數字指定類,整理如下:
1 特殊符號類:
表示法:
比對:
等同符號表示:
\a
Alert character.


\b
Backspace character.
\u0008
\e
Escape character(ESC)
\u001B
\n
Newline
\u000A
\B
Backslash
\\
\0
NULL
\u0000
\r
Carriage return
\u000D
\t
Horizontal tab
\u0009
\f
Form feed
\u000C
\v
Vertical tab
\u000B
\cx
Control-x



2 字集類:
表示法
比對
等同表示法
\d, \D
數字, 非數字
[[:digit:]] ,[^[:digit:]]
\s, \S
空白類字符,非空白類字符
[[:space:]] , [^[:space:]]
\w, \W
字母+數字+底線, 非以上組合
[[:alnum:]_] , [^[:alnum:]_]

3  定位字符類:
表示法
比對:
\A, \Z
字串開頭, 字串結尾
*還沒找到相對應的範例
\m, \M
單字開頭, 單字結尾 [[:<:]] [[:>:]]
\y, \Y
單字開頭或單字結尾, \y
*還沒找到相對應的範例

4  數字指定類:
表示法:
比對:
\unnnn, \Unnnnnnnn
16-bits, 32-bits Unicode character code.
\xhh Consumes all hex digits after \x.
An 8-bit hexadecimal character code.
\x, \xy, \xyz
xyz為數字,這個可以是back reference,或者是8-bit octal character code

  1. Nongreedy(非貪婪?這怎麼翻(yay))
之前提過RE的規則是愈長愈好,設定Nongreedy即是變成愈短愈好,使用的是? 加在第三項的數量(quantifiers)比對後面,比如說我們要match整個輸入中的第一行,如果寫:
.+\n 這樣會match整個輸入,直到最後一個\n符號,其中包括很多很多換行符號。
.+?\n 設定+nongreedy,則遇到第一個\n就會結束比對
或者我們要抓<title></title>中間的文字:
<title>(.*?)</title>
所有的數量比對加?在後面都會變成non-greedy??代表0次優先,{1,3}?則會以1,2,3的順序去match

  1. Back referencelook ahead
這個規則比較重在要把內容存到暫存裡的狀況,一般的狀況下似乎不太用到。
在正規表示式中除了直接match的結果外,還可以用小括號()來記錄子比對的結果:
例如<title>(.*?)</title>,除了match整段文字外,可以取出兩個tag中間的文字內容。
要取出這個這個比對結果,可以用Back reference,使用的方式是\xx為數字,依數字對應到各子比對結果,子比對結果的排序為“外到內,左到右”,如下所示:
(())(),注意()是包括自己跟()的內容。

另一方面,如果我們只想要比對,卻懶得管一些比對的內容呢?這就需要look ahead,我想到最需要誕個功能的地方是rename,我要改掉所有txt檔,卻只要取出檔名的部分,這時候就需要look ahead'
例如我要取出副檔名為.txt的文件名稱:
^.*\.txt$,可以,但記錄下來的是:lalala.txt.txt是不需要記錄的
positive look ahead^.*(?=\.txt)$,記錄的就只有lalala
negative look ahead^.*(?!\.txt)$,這反過來,比對出非.txt結尾的檔案名稱。
還有一個是(?:pattern),同樣也是不記錄pattern中的內容,但跟look-ahead的差異點在哪我就不是很確定了。

其實主要的功能就上述這些,我覺得主要會用到的大概只到第6點,我在vim會用到第8點,我提的那本書還有兩個功能,一個是collating element [.identifier.],只是書裡沒說得很清楚,我也還沒試出幹什麼用的…;另一個是Equivalent class [=char=],只有比對Unicode例如[=o=]可以比對 o, ō, ŏ,但平常好像也用不到。
這篇主要整理規則,之後會寫一篇有關應用方面的實例與方法。

如果是有關C語言中,有關scanf的部分,可以參考scanf的整理,一些基本的正規表示法語法在scanf中其實是有支援的,請見: