2013年12月21日

Gentoo編譯scipy(with intel MKL)

在gentoo安裝好mkl後,依照官方的說明
http://software.intel.com/en-us/articles/numpyscipy-with-intel-mkl
依序安裝numpy, scipy,
在numpy的部份順利完成,但是在scipy的部份,安裝完後使用
import scipy時,出現

ImportError: /usr/lib64/python2.7/site-packages/scipy/sparse/sparsetools/_csr.so: undefined symbol: __intel_sse4_strlen

原因如下,C/C++ 有完整的「編譯 -> 連結 -> 執行」三個階段, 各階段都可能發生 undefined symbol。在解決惱人的 undefined symbol 前, 得先明白整個編譯流程:
  1. 編譯 .c / .cpp 為 .o (object file) 時, 需要提供 header 檔 (用到 gcc 參數 -I)。事實上, 在編譯單一檔案時, gcc/g++ 根本不在意真正的 symbol 是否存在, 反正有宣告它就信了, 所以有引對 header 即可。這也是可分散編譯的原因, 程式之間在編譯成 .o 檔時, 並沒有相依性。
  2. 用 linker (ld 或 gold) 將 *.o 連結成 dynamic library 或執行檔時, 需要提供要連結的 library (用到 gcc 參數 -L 指定目錄位置, 用 -l 指定要連什麼函式庫)。不同於前一步, 此時 symbol 一定要在。
  3. 執行的時候, 會再動態開啟 shared library 讀出 symbol。換句話說, 前一個步驟只是檢查是否有。檢查通過也連結成 executable 或 shared library 後, 若執行時對應的檔案不見了, 仍會在執行期間找不到 symbol。若位置沒設好, 可能需要用 LIB_LIBRARY_PATH 指定動態函式的位置, 但不建議這麼做, 最好在執行 linker 時就指定好位置。
就看 undefined symbol 發生在那個階段, 若是編 object file 時發生, 就是沒和編譯器說 header 檔在那, 記得用 -I 告訴它。若在 linking 時發生, 就要同時設好 -L 和 -l。不過難就難在要去那找 undefined symbol 的出處。

因為我的問題是發生在執行時間,所以屬於第3類。
首先使用nm _csr.so或是objdump -x _csr.so確認連結。

而 __intel_sse4_strlen定義在
/opt/intel/lib/intel64/libirc.so
/opt/intel/lib/intel64/libiomp5.so

#使用ldconfig -p確認mkl設定(需root權限)
#ldconfig -p|grep mkl
 libiomp5.so (libc6,x86-64) => /opt/intel/composerxe/lib/intel64/libiomp5.so
libirc.so (libc6,x86-64) => /opt/intel/composerxe/lib/intel64/libirc.so

#檢查檔案的格式
$file _csr.so

_csr.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped

#使用ldd -r查看缺少的symbol
$ldd -r _csr.so

linux-vdso.so.1 =>  (0x00007fff207ff000)
        libpython2.7.so.1.0 => /usr/lib64/libpython2.7.so.1.0 (0x00007f3757ffe000)
        libstdc++.so.6 => /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/libstdc++.so.6 (0x00007f3757cf4000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f3757a72000)
        libgcc_s.so.1 => /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/libgcc_s.so.1 (0x00007f375785c000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f37574d2000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f37572b5000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f37570b1000)
        libutil.so.1 => /lib64/libutil.so.1 (0x00007f3756ead000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f37587e8000)
undefined symbol: __intel_sse4_strlen   (./_csr.so)
undefined symbol: _intel_fast_memset    (./_csr.so)
undefined symbol: _intel_fast_memcpy    (./_csr.so)
undefined symbol: __intel_sse4_strncmp  (./_csr.so)
undefined symbol: __intel_sse4_strcpy   (./_csr.so)
undefined symbol: __intel_sse4_strncpy  (./_csr.so)
undefined symbol: __intel_sse4_strcat   (./_csr.so)

解法方法:
首先在編譯scipy時,使用以下的指令:
  1. python setup.py config --compiler=intelem --fcompiler=intelem build_clib --compiler=intelem  --fcompiler=intelem build_ext --compiler=intelem --fcompiler=intelem install >>build.log
    將編譯時期的log寫進build.log中
  2. cat build.log|grep _csr.so, 可得到
    c++ -shared build/temp.linux-x86_64-2.7/scipy/sparse/sparsetools/csr_wrap.o -L/usr/lib64 -Lbuild/temp.linux-x86_64-2.7 -lpython2.7 -o build/lib.linux-x86_64-2.7/scipy/sparse/sparsetools/_csr.so
    copying build/lib.linux-x86_64-2.7/scipy/sparse/sparsetools/_csr.so -> /usr/lib64/python2.7/site-packages/scipy/sparse/sparsetools
    由於已知道是linking的時候有問題,所以在scipy目錄下,將上述編譯指令改成:
    c++ -shared build/temp.linux-x86_64-2.7/scipy/sparse/sparsetools/csr_wrap.o -L/opt/intel/lib/intel64 -L/usr/lib64 -Lbuild/temp.linux-x86_64-2.7 -lpython2.7 -lirc -o build/lib.linux-x86_64-2.7/scipy/sparse/sparsetools/_csr.so
  3. 完成編譯後,將編譯完成的檔案拷貝到系統目錄下(需root權限)
    cp build/lib.linux-x86_64-2.7/scipy/sparse/sparsetools/_csr.so /usr/lib64/python2.7/site-packages/scipy/sparse/sparsetools
  4. 全部完成後,使用import scipy.sparses(scipy.stats)來確認問題解決。
除了_csr.so之後,還有幾個檔案_csc.so, _coo.so, _dia.so, _bsr.so, _csgraph都是用上述方法解決。

_bsr.so除了-lirc外,還需加上-lsvml.





2013年12月18日

快速取出matrix diagonal element方法

n = 1000
c = 20
a = np.random.rand(n,n)

a[np.diag_indices_from(a)] /= c # 119 microseconds
a.flat[::n+1] /= c # 25.3 microseconds
 
#取出off diagonal的方法
 np.delete(a, a.ravel()[::n+1])

2013年12月13日

iptables保存


iptables的設定在在每次重開機之後就會消失
所以設定完後可以用iptables-save將設定檔存起來,如:
sudo iptables-save > /etc/iptables-rules


但是存起來之後,他並不會幫你在每次重開機都讀那個檔

所以還要再設定,修改/etc/network/interfaces,最後面加上:
pre-up iptables-restore < /etc/iptables-rules

2013年12月12日

fast rolling window

假設有兩個array S1 (size m), S2 (size n), m>n,要計算S2相對於S1的滑動函數值(如mean或是std等),一般的做法是使用loop實作,但是python的迴圈速度相當的慢,所以建議使用numpy strides的功能來加速,在測試當中,計算stdev大約能夠加速100倍,程式碼如下:

def rolling_window(a, window):
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    print shape
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

def test_rolling_window(winsize=3):
    import time
    t = time.clock()
    observations = np.random.randn(1000)
    np.std(rolling_window(observations, winsize), 1)
    print "strided %.6f secs"%(time.clock()-t)

    t = time.clock()
    for idx in xrange(winsize, len(observations)):
        np.std(observations[idx-winsize: idx])
    print "loop %.6f secs"%(time.clock()-t)

2013年10月1日

numpy multiply broadcast by column

假設array a的size為(2,5),array c的size為(2,),如果要做elementwise multiplication時,我的做法:
(a.T*c).T
但是這個做法需要寫到兩次transpose,式子變長時不易理解。

後來在trace別人的code時,看到了以下的寫法:
a*c[:, np.newaxis]
即可達到相同的效果,且較容易理解。

2013年8月10日

[Theano] 在Eclipse中使用GPU執行程式

首先在{HOME}下建立.theanorc檔案,內容如下:
 [global] floatX = float32
 device = gpu0 
 [nvcc] fastmath = True 
存檔後,退出至{HOME}中。 
輸入nvcc指令測試cuda套件是否已經安裝完成。 

然後到eclipse隨便建立一個python檔,import theano後,執行該程式, 此時可能會出現以下錯誤:
 ERROR (theano.sandbox.cuda): nvcc compiler not found on $PATH. Check your nvcc installation and try again.

 這是因為eclipse的pydev套件使用的PATH變數與linux中不同,
用以下指令修正:
 window->preferences->PyDev->Interpreter-Python->Environment->New-> Name: PATH, Value: ${env_var:PATH}:/usr/local/cuda-5.0/bin 

設定完成後,可在python檔使用
 import os 
print os.environ['PATH'] 
 確定環境變數修改完成。

2013年5月11日

[R] install.packages without graphics

由於我經常使用linux + screen的方式在遠端執行R ,在安裝R套件時無法使用graphics套件來選擇mirror,所以改用以下的方式在console下設定mirror site後,再來安裝套件。
chooseCRANmirror(graphics=FALSE);
install.packages("pkgName")
即可安裝套件。

2013年3月16日

postgresql備份與還原

 OS: Ubuntu 12.04 & Postgresql 9.1
因為備份與還原資料時,需要相當長的時間,因此我所使用的備份與還原的工具都是在screen環境下使用pg_backup備份,psql還原。

備份
  • pg_dump -h [host](localhost) -F [format, p: sql script(default), t: tar, c: compress] [資料庫名稱 ] -U [帳號] -f [備份檔名稱.sql] -v
  • 以db_chenhh這個帳號,備份investment資料庫,則命令:pg_dump investment -U db_chenhh -f investment_backup.sql

還原
  • 命令:psql -f [備份檔名稱.sql] [資料庫] [帳號]
  • psql -f investment_backup.sql investment db_chehh
  • 命令: pg_restore, 參數與pg_dump相同
  • pg_restore -f investment_backup.sql investment


2013年3月9日

更換BLAS implementation

使用openBLAS替換ATLAS(Ubuntu 12.04)
  1. sudo apt-get install libopenblas-base, libopenblas-dev
  2. sudo update-alternatives --all
  3. set liblapack.so.3gf to/usr/lib/lapack/liblapack.so.3gf

其它的BLAS替代方案可參考Debian wiki:http://wiki.debian.org/DebianScience/LinearAlgebraLibraries

2013年2月5日

linux新增字型

OS: ubuntu 12.04 
新增字型的方法:
  1. 在/usr/share/fonts新增資料夾(e.g. winfonts)
  2. 將字型檔案copy至/usr/share/fonts/winfonts/
  3. 執行sudo fc-cache -f -v

2013年1月21日

postgresql連線問題(beta)


  1. Cdbexception
  2. 這是一個連線數超過資料程式庫限制連線數的的問題。
    首先檢視一下資料庫內,現在的連線數:
    • postgres=# select count(1) from pg_stat_activity; #目前連線數
    • postgres=# show max_connections; #系統最大連線數
    • postgres=# show superuser_reserved_connections; #保留給superuser的連線數
    解決方法:
    • 增大postgresql.conf中的參數max_connections或superuser_reserved_connections 值(修改這兩個參數都需要重啟DB)
    • 開發程式上檢查連線數是否正常關閉等,應急情況下,可把pg_stat_activity中IDLE的程式移除,kill procpid;

  3. psql: could not connect to server: Connection refused (0x0000274D/10061)
  4. 這個問題一般是以下原因造成的:
    • 伺服器沒起來,ps -ef|grep postgres檢視是否存在PG程式
    • 監聽問題,cat postgresql.conf|grep listen 檢視監聽位址是否正確
    • 服務端高階使用者能進去,其他用戶不行,檢查是否超出最大連線數限制
    • 以上都沒問題,伺服器端能連進去,但用戶端不行,這時需要檢視pg_hba.conf檔案
    • 以上都沒問題,檢查伺服器端的iptables,開啟防火牆的存取通訊埠

Postgresql pg_hba.conf

for Ubuntu 12.04, postgresql 9.1
檔案位置:/etc/postgresql/9.1/main/pg_hba.conf

pg_hba.conf修改後,需使用pg_ctl reload重新讀取pg_hba.conf檔,如果pg_ctl找不到資料庫,則用-D /.../pgsql/data/ 指定資料庫目錄,或export PGDATA=/.../pgsql/data/ 導入環境變數。

用來設定postgre資料庫的使用者存取權限, 檔案主要有5個欄位:
  1. Type: host表遠端存取,local表本機端存取 
  2. Database: 設定可存取的Database 
  3. User: 設定可存取的使用者 
  4. Address: 設定可存取之網域,此設定全部網域皆可存取 
  5. Method: trust表不需認證,password表示需要密碼
TYPE定義了多種連接PostgreSQL的方式,分別是:
  • local: 使用本地unix socket
  • host: 使用TCP/IP連接(包括SSL和非SSL)
  • host結合IPv4 address:使用IPv4方式
  • host結合IPv6 address:則使用IPv6方式
  • hostssl只能使用SSL TCP/IP連接
  • hostnossl不能使用SSL TCP/IP連接
DATABASE指定符合條件的某個資料庫是多個資料庫,庫名間以逗號分隔。
All: 只有在沒有其他的符合條目時才代表「所有資料庫」如果有其他的符合條目則代表「除了該條之外的資料庫」,因為“all”的優先順序最低。如下例:
local    db1    user1    reject
local    all      all      ident
這兩條都是指定local訪問方式,因為前一條指定了特定的資料庫db1,所以後一條的all代表的是除了db1之外的資料庫,同理使用者的all也是這個道理。

USER指定哪個資料庫使用者(PostgreSQL正規的名稱是角色,role)。多個用戶以逗號分隔。

CIDR-ADDRESS項local方式不必填寫,該項可以是IPv4位址或IPv6位址,可以定義某台主機或某個網段。

METHOD指定如何處理用戶端的認證。常用的有ident,md5,password,trust,reject。
  • dent是Linux下PostgreSQL預設的local認證方式,凡是能正確登錄伺服器的作業系統使用者(注:不是資料庫使用者)就能使用本使用者映射的資料庫使用者不需密碼登錄資料庫。用戶映射檔為pg_ident.conf,這個檔記錄著與作業系統使用者匹配的資料庫使用者,如果某作業系統使用者在本檔中沒有映射用戶,則預設的映射資料庫使用者與作業系統使用者同名。比如,伺服器上有名為user1的作業系統使用者,同時資料庫上也有同名的資料庫使用者,user1登錄作業系統後可以直接輸入psql,以user1資料庫使用者身份登錄資料庫且不需密碼。很多初學者都會遇到psql -U username登錄資料庫卻出現“username ident 認證失敗”的錯誤,明明資料庫使用者已經createuser。原因就在於此,使用了ident認證方式,卻沒有同名的作業系統使用者或沒有相應的映射用戶。解決方案:1、在pg_ident.conf中添加映射用戶;2、改變認證方式。
  • md5是常用的密碼認證方式,如果你不使用ident,最好使用md5。密碼是以md5形式傳送給資料庫,較安全,且不需建立同名的作業系統使用者。
  • password是以純文字密碼傳送給資料庫,建議不要在生產環境中使用。
  • trust是只要知道資料庫用戶名就不需要密碼或ident就能登錄,建議不要在生產環境中使用。
  • reject是拒絕認證。
  • 本地使用psql登錄資料庫,是以unix通訊端的方式,附合local方式。
  • 使用PGAdmin3或php登錄資料庫,不論是否本地均是以TCP/IP方式,符合host方式。

2013年1月18日

PgBouncer

PgBouncer 是 PostgreSQL 的輕量的連接池,支援三種模式。
  1. Session pooling/會話連接池
    最禮貌的方法。在客戶端連接的時候,在它的連接生命期內,會給它賦予一個服務器連接。在客戶端斷開的時候,服務器連接會放回到連接池中。 
  2. Transaction pooling/事務連接池
    服務器連接只有在一個事務裡的時候才賦予客戶端。在 PgBouncer 注意到事務結束的時候,服務器將會放回連接池中。這是一個 hack,因為它打破了應用對後段連接的看法。只有在應用配合這樣的使用模式,沒有使用會破壞這種使用模式的時候才能用這個連接方式。參閱下標獲取會破壞 這種模式的特性。 
  3. Statement pooling/語句連接池
    最激進的模式。這是事務連接池的一個扭曲的變種 - 不允許多語句的事務。這就意味著是在客戶端強制“autocomit”模式,主要是給 PL/Proxy 用的。
setting in Ubuntu 12.04
  • 安裝:sudo apt-get install pgbouncer
  • 設定檔:位於/etc/pgbouncer資料夾下,pgbouncer.ini為主要設定檔,userlist.txt為可連線的使用者(在 pgbounce.ini中指定)。
  • man pgbouncer可以看到manaul中提供的一個簡單配置的例子 。
  • [databases]
    pg_template1 = host=127.0.0.1 dbname=template1
    [pgbouncer]
    pool_mode = session
    listen_port = 6543
    listen_addr = 127.0.0.1
    auth_type = md5
    auth_file = users.txt
    logfile = pgbouncer.log
    pidfile = pgbouncer.pid
    admin_users = someuser
    stats_users = stat_collector
       
  • 上面的配置說明了該pgbouncer創建了針對127.0.0.1上的template1的一個連接池,該連接池對調用方的呈現的資料庫名稱是pg_template1,它映射到了template1上。所有訪問pbbouncer上的pg_template1的請求都會轉到template1上完成。
  • pool_mode 指明了連接池的模型,pgbouncer目前支援三種連接池模型。分別是session, transaction和statment三個級別。 
  •  a. session. 會話級連結。只有與當用戶端的會話結束時,pgbouncer才會收回已分配的連結 
  •  b. transaction 事務級連接。當事務完成後,pgbouncer會回收已分配的連結。也就是說用戶端只是在事務中才能獨佔此連結,非事務的對資料庫的請求是沒有獨享的連結的。 
  •  c. statement 語句級連結。任何對資料庫的請求完成後,pgbouncer都會回收連結。此種模式下,用戶端不能使用事務,否則會造成資料的不一致。 pgbouncer的預設設置是session連結。
  • listen_port和listen_addr是pgbouncer監聽的位址和埠號。
  • auth_type和auth_file是bppgbouncer用以完成用戶端身份認證。auth_file中保存用戶名和密碼,根據驗證方式(auth_type)的不同,auth_file的內容也有不同。 
  •  md5: 基於md5的密碼驗證,
  • auth_file中需要有普通文本和md5值兩種形式的密碼; 
  •  crypt: 基於crypt的密碼驗證(man 3 crypt), auth_file必須包含文本密碼; 
  •  plain: 明文驗證方式; 
  •  trust: 不進行驗證,但auth_file依然需要保存用戶名; 
  •  any: 也不進行驗證,而且auth_file中不需要保存用戶名了。但此種方式需要在pg_template1中明確說明用戶名進行真實資料庫的登錄。如: pg_template1 = host=127.0.0.1 user=exampleuser dbname=template1.否則會報錯的。 需要說明的是:auth_file中的用戶名、密碼都必須使用雙引號,否則還是報錯。
  • logfile和pidfile分別保存log檔和pid檔的路徑。 
  •  admin_users:列出哪些用戶可以登錄pgbouncer進行管理,以逗號進行分隔 stats_users:列出哪些用戶可以登錄pgbouncer進行唯讀操作,如可以列出伺服器狀態,訪問連結等,但是不能執行reload。

2013年1月17日

Postgresql 9.1安裝(Ubuntu 12.04)

安裝
  • $sudo apt-get install postgresql
  • #查詢已安裝的版本: psql -V 
  • #改變postgres user密碼: sudo passwd postgres
  • #變更為postgres user: su - postgres
  • #進入psql console: psql postgres
  • #上述三步驟可簡化為: sudo -u postgres psql postgres
  • 在psql中修改postgres帳號的密碼: ALTER USER postgres WITH PASSWORD '';
設定
  • 所有設定檔都在/etc/postgresql資料夾下
    sudo vim /etc/postgresql/9.1/main/postgresql.conf(主要設定檔)設定listen_address='localhost' (只有本機可連線)
    or listen_address='*' (本機所有介面均可連線)
  • 启用密码验证:
    #password_encryption = on改为password_encryption = on 
  • ph_hba.conf(可訪問的client ip range)
    在文档末尾加上以下内容
    # to allow your client visiting postgresql server
    host all all 0.0.0.0 0.0.0.0 md5
  • share memory of os
    http://www.postgresql.org/docs/9.1/static/kernel-resources.html
    在/etc/sysctl.conf中設定
    kernels.shmmax=9663676416 #(9G, 9*2^9)
    kernels.shmall=2359296          #(9G/4096k)
  • 完成後,重新啟動pgsql服務:service postgresql restart