2015年3月24日 星期二

EtherCAT


節錄自 http://zh.wikipedia.org/wiki/EtherCAT

EtherCAT乙太網控制自動化技術[1])是一個開放架構,以乙太網為基礎的現場總線系統,其名稱的CAT為控制自動化技術(ControlAutomation Technology)字首的縮寫。EtherCAT是確定性的工業以太網,最早是由德國的Beckhoff公司所研發[2]
自動化對通訊一般會要求較短的資料更新時間(或稱為週期時間)、資料同步時的通訊抖動量低,而且硬體的成本要低,EtherCAT開發的目的就是讓乙太網可以運用在自動化應用中。

OpenMP


官網 http://openmp.org/

以下節錄自 http://zh.wikipedia.org/wiki/OpenMP


OpenMP(Open Multi-Processing)是一套支持跨平台共享內存方式的多執行緒並發的編程API,...,可以在大多數的處理器體系和作業系統中運行,包括Solaris, AIX, HP-UX, GNU/Linux, Mac OS X, 和Microsoft Windows。包括一套編譯器指令、庫和一些能夠影響運行行為的環境變量。

OpenMP是由OpenMP Architecture Review Board牽頭提

出的,並已被廣泛接受的,用於共享內存並行系統的多執行緒程序設計的一套指導性注釋(Compiler Directive)。...。OpenMP提供了對並行算法的高層的抽象描述,程式設計師通過在原始碼中加入專用的pragma來指明自己的意圖,由此編譯器可以自動將程序進行並行化,並在必要之處加入同步互斥以及通信。當選擇忽略這些pragma,或者編譯器不支持OpenMP時,程序又可退化為通常的程序(一般為串行),代碼仍然可以正常運作,只是不能利用多執行緒來加速程序執行。

OpenMP支持的程式語言包括C語言C++Fortran

介紹

OpenMP是一個跨平台的多執行緒實現,主執行緒(順序的執行指令)生成一系列的子執行緒,並將任務劃分給這些子執行緒進行執行。這些子執行緒並行的運行,由運行時環境將執行緒分配給不同的處理器。

要進行並行執行的代碼片段需要進行相應的標記,用預編譯指令使得在代碼片段被執行前生成執行緒,每個執行緒會分配一個id,可以通過函數(called omp_get_thread_num())來獲得該值,該值是一個整數,主執行緒的id為0。在並行化的代碼運行結束後,子執行緒join到主執行緒中,並繼續執行程序。

默認情況下,各個執行緒獨立的執行並行區域的代碼。可以使用Work-sharing constructs來劃分任務,使每個執行緒執行其分配部分的代碼。通過這種方式,使用OpenMP可以實現任務並行數據並行

運行時環境分配給每個處理器的執行緒數取決於使用方法、機器負載和其他因素。執行緒的數目可以通過環境變量或者代碼中的函數來指定。在C/C++中,OpenMP的函數都聲明在頭文件omp.h中。

語法

#pragma omp  [clause[[,] clause] ...]

directive

其中,directive共11個:
  • atomic 內存位置將會原子更新(Specifies that a memory location that will be updated atomically.)
  • barrier 執行緒在此等待,直到所有的執行緒都執行到此barrier。用來同步所有執行緒。
  • critical 其後的代碼塊為臨界區,任意時刻只能被一個執行緒執行。
  • flush 所有執行緒對所有共享對象具有相同的內存視圖(view of memory)
  • for 用在for循環之前,把for循環並行化由多個執行緒執行。循環變量只能是整型
  • master 指定由主執行緒來執行接下來的程式。
  • ordered 指定在接下來的代碼塊中,被並行化的 for循環將依序執行(sequential loop)
  • parallel 代表接下來的代碼塊將被多個執行緒並行各執行一遍。
  • sections 將接下來的代碼塊包含將被並行執行的section塊。
  • single 之後的程式將只會在一個執行緒(未必是主執行緒)中被執行,不會被並行執行。
  • threadprivate 指定一個變量是執行緒局部存儲(thread local storage)

clause

共計13個clause:
  • copyin 讓threadprivate的變量的值和主執行緒的值相同。
  • copyprivate 不同執行緒中的變量在所有執行緒中共享。
  • default Specifies the behavior of unscoped variables in a parallel region.
  • firstprivate 對於執行緒局部存儲的變量,其初值是進入並行區之前的值。
  • if 判斷條件,可用來決定是否要並行化。
  • lastprivate 在一個循環並行執行結束後,指定變量的值為循環體在順序最後一次執行時取得的值,或者#pragma sections在中,按文本順序最後一個section中執行取得的值。
  • nowait 忽略barrier的同步等待。
  • num_threads 設定執行緒數量的數量。默認值為當前計算機硬體支持的最大並發數。一般就是CPU的內核數目。超執行緒被作業系統視為獨立的CPU內核。
  • ordered 使用於 for,可以在將循環並行化的時候,將程式中有標記 directive ordered 的部份依序執行。
  • private 指定變量為執行緒局部存儲。
  • reduction Specifies that one or more variables that are private to each thread are the subject of a reduction operation at the end of the parallel region.
  • schedule 設定for循環的並行化方法;有 dynamic、guided、runtime、static 四種方法。
    • schedule(static, chunk_size) 把chunk_size數目的循環體的執行,靜態依序指定給各執行緒。
    • schedule(dynamic, chunk_size) 把循環體的執行按照chunk_size(預設值為1)分為若干組(即chunk),每個等待的執行緒獲得當前一組去執行,執行完後重新等待分配新的組。
    • schedule(guided, chunk_size) 把循環體的執行分組,分配給等待執行的執行緒。最初的組中的循環體執行數目較大,然後逐漸按指數方式下降到chunk_size。
    • schedule(runtime) 循環的並行化方式不在編譯時靜態確定,而是推遲到程序執行時動態地根據環境變量OMP_SCHEDULE 來決定要使用的方法。
  • shared 指定變量為所有執行緒共享。


OpenMP的庫函數

OpenMP定義了20多個庫函數:
1.void omp_set_num_threads(int _Num_threads);
在後續並行區域設置執行緒數,此調用只影響調用執行緒所遇到的同一級或內部嵌套級別的後續並行區域.說明:此函數只能在串行代碼部分調用.
2.int omp_get_num_threads(void);
返回當前執行緒數目.說明:如果在串行代碼中調用此函數,返回值為1.
3.int omp_get_max_threads(void);
如果在程序中此處遇到未使用 num_threads() 子句指定的活動並行區域,則返回程序的最大可用執行緒數量.說明:可以在串行或並行區域調用,通常這個最大數量由omp_set_num_threads()或OMP_NUM_THREADS環境變量決定.
4.int omp_get_thread_num(void);
返回當前執行緒id.id從1開始順序編號,主執行緒id是0.
5.int omp_get_num_procs(void);
返回程序可用的處理器數.
6.void omp_set_dynamic(int _Dynamic_threads);
啟用或禁用可用執行緒數的動態調整.(預設情況下啟用動態調整.)此調用只影響調用執行緒所遇到的同一級或內部嵌套級別的後續並行區域.如果 _Dynamic_threads 的值為非零值,啟用動態調整;否則,禁用動態調整.
7.int omp_get_dynamic(void);
確定在程序中此處是否啟用了動態執行緒調整.啟用了動態執行緒調整時返回非零值;否則,返回零值.
8.int omp_in_parallel(void);
確定執行緒是否在並行區域的動態範圍內執行.如果在活動並行區域的動態範圍內調用,則返回非零值;否則,返回零值.活動並行區域是指 IF 子句求值為 TRUE 的並行區域.
9.void omp_set_nested(int _Nested);
啟用或禁用嵌套並行操作.此調用只影響調用執行緒所遇到的同一級或內部嵌套級別的後續並行區域._Nested 的值為非零值時啟用嵌套並行操作;否則,禁用嵌套並行操作.預設情況下,禁用嵌套並行操作.
10.int omp_get_nested(void);
確定在程序中此處是否啟用了嵌套並行操作.啟用嵌套並行操作時返回非零值;否則,返回零值.
互斥鎖操作 嵌套鎖操作 功能
11.void omp_init_lock(omp_lock_t * _Lock); 12. void omp_init_nest_lock(omp_nest_lock_t * _Lock);
初始化一個(嵌套)互斥鎖.
13.void omp_destroy_lock(omp_lock_t * _Lock); 14.void omp_destroy_nest_lock(omp_nest_lock_t * _Lock);
結束一個(嵌套)互斥鎖的使用並釋放內存.
15.void omp_set_lock(omp_lock_t * _Lock); 16.void omp_set_nest_lock(omp_nest_lock_t * _Lock);
獲得一個(嵌套)互斥鎖.
17.void omp_unset_lock(omp_lock_t * _Lock); 18.void omp_unset_nest_lock(omp_nest_lock_t * _Lock);
釋放一個(嵌套)互斥鎖.
19.int omp_test_lock(omp_lock_t * _Lock); 20.int omp_test_nest_lock(omp_nest_lock_t * _Lock);
試圖獲得一個(嵌套)互斥鎖,並在成功時放回真(true),失敗是返回假(false).
21.double omp_get_wtime(void);
獲取wall clock time,返回一個double的數,表示從過去的某一時刻經歷的時間,一般用於成對出現,進行時間比較. 此函數得到的時間是相對於執行緒的,也就是每一個執行緒都有自己的時間.
22.double omp_get_wtick(void);
得到clock ticks的秒數.


例子

在 omp parallel 段內的程序代碼由多線程來執行:
 int main(int argc, char* argv[])
 {
  #pragma omp parallel  
   printf("Hello, world.\n");
 
   return 1;
 }
執行結果
% gcc omp.c (由單線程來執行)
% ./a.out
Hello, world.

% gcc -fopenmp omp.c (由多線程來執行)
% ./a.out
Hello, world.
Hello, world.
Hello, world.
Hello, world.

環境變量

OpenMP可以使用環境變量 OMP_NUM_THREADS以控制執行線程的數量。

例子

% gcc -fopenmp omp.c 

% setenv OMP_NUM_THREADS 2(由2線程來執行)
setenv是CSH的指令

在bash shell 環境中 要用export 
% export OMP_NUM_THREADS=2 (由2線程來執行)

% ./a.out
Hello, world.
Hello, world.

優點和缺點

優點
  • 可移植的多執行緒代碼(在C/C++和其他語言中,人們通常為了獲得多執行緒而調用特定於平台的原語)
  • 簡單,沒必要向MPI中那樣處理消息傳遞
  • 數據分布和分解由指令自動完成
  • 增量並行,一次可以只在代碼的一部分執行,對代碼不需要顯著的改變
  • 統一的順序執行和並行執行的代碼,在順序執行編譯器上,OpenMP的執行按照注釋進行對待;
  • 在一般情況下,使用OpenMP並行時原始的(串行)代碼語句不需要進行修改,這減少不經意間引入錯誤的機會。
  • 同時支持粗粒度和細粒度的並行
缺點
  • 存在引入難以調試的同步錯誤和競爭條件的風險
  • 目前,只能在共享內存的多處理器平台高效運行
  • 需要一個支持OpenMP的編譯器
  • 可擴展性是受到內存架構的限制
  • 不支持比較和交換
  • 缺乏可靠的錯誤處理
  • 缺乏對執行緒與處理器映射的細粒度控制
  • GPU上不能使用
  • 很容易出現一些不能共享的代碼
  • 多執行緒的可執行文件的啟動需要更多的時間,可能比單執行緒的運行的慢,因此,使用多執行緒一定要有其他有優勢的地方
  • 很多情況下使用多執行緒不僅沒有好處,還會帶來一些額外消耗

OpenCL


節錄自 http://zh.wikipedia.org/wiki/OpenCL

OpenCL (Open Computing Language,開放計算語言) 是一個為異構平台編寫程式的框架,此異構平台可由 CPU GPU 或其他型別的處理器組成。 OpenCL 由一門用於編寫 kernels (在 OpenCL 裝置上執行的函式)的語言(基於 C99 )和一組用於定義並控制平台的 API 組成。 OpenCL 提供了基於任務分割和資料分割的並列計算機制。

2015年3月23日 星期一

Mommy Needs a Raise !






H.264



原文 http://blog.sina.com.cn/s/blog_8fb8cd4801018yyo.html


----------------------
前言
-----------------------
        H264是新一代的編碼標準,以高壓縮高質量和支持多種網絡的流媒體傳輸著稱,在編碼方面,我理解的他的理論依據是:參照一段時間內圖像的統計結果表明,在相鄰幾幅圖像畫面中,一般有差別的像素只有10%以內的點,亮度差值變化不超過2%,而色度差值的變化只有1%以內。所以對於一段變化不大圖像畫面,我們可以先編碼出一個完整的圖像幀A,隨後的B幀就不編碼全部圖像,只寫入與A幀的差別,這樣B幀的大小就只有完整幀的1/10或更小!B幀之後的C幀如果變化不大,我們可以繼續以參考B的方式編碼C幀,這樣循環下去。這段圖像我們稱為一個序列(序列就是有相同特點的一段數據),當某個圖像與之前的圖像變化很大,無法參考前面的幀來生成,那我們就結束上一個序列,開始下一段序列,也就是對這個圖像生成一個完整幀A1,隨後的圖像就參考A1生成,只寫入與A1的差別內容。
        在H264協議裡定義了三種幀,完整編碼的幀叫I幀,參考之前的I幀生成的只包含差異部分編碼的幀叫P幀,還有一種參考前後的幀編碼的幀叫B幀。
        H264採用的核心算法是幀內壓縮和幀間壓縮,幀內壓縮是生成I幀的算法,幀間壓縮是生成B幀和P幀的算法。



----------------------
序列的說明
----------------------
        在H264中圖像以序列為單位進行組織,一個序列是一段圖像編碼後的數據流,以I幀開始,到下一個I幀結束。
        一個序列的第一個圖像叫做IDR圖像(立即刷新圖像),IDR圖像都是I幀圖像。H.264引入IDR圖像是為了解碼的重同步,當解碼器解碼到IDR圖像時,立即將參考幀隊列清空,將已解碼的數據全部輸出或拋棄,重新查找參數集,開始一個新的序列。這樣,如果前一個序列出現重大錯誤,在這裡可以獲得重新同步的機會。IDR圖像之後的圖像永遠不會使用IDR之前的圖像的數據來解碼。
        一個序列就是一段內容差異不太大的圖像編碼後生成的一串數據流。當運動變化比較少時,一個序列可以很長,因為運動變化少就代表圖像畫面的內容變動很小,所以就可以編一個I幀,然後一直P幀、B幀了。當運動變化多時,可能一個序列就比較短了,比如就包含一個I幀和3、4個P幀。


-----------------------
三種幀的說明
-----------------------
I幀:幀內編碼幀,I幀表示關鍵幀,你可以理解為這一幀畫面的完整保留;解碼時只需要本幀數據就可以完成(因為包含完整畫面)

I幀特點: 
1.它是一個全幀壓縮編碼幀。它將全幀圖像信息進行JPEG壓縮編碼及傳輸; 
2.解碼時僅用I幀的數據就可重構完整圖像; 
3.I幀描述了圖像背景和運動主體的詳情; 
4.I幀不需要參考其他畫面而生成; 
5.I幀是P幀和B幀的參考幀(其質量直接影響到同組中以後各幀的質量); 
6.I幀是幀組GOP的基礎幀(第一幀),在一組中只有一個I幀; 
7.I幀不需要考慮運動矢量; 
8.I幀所佔數據的信息量比較大。 

P幀:前向預測編碼幀。P幀表示的是這一幀跟之前的一個關鍵幀(或P幀)的差別,解碼時需要用之前緩存的畫面疊加上本幀定義的差別,生成最終畫面。(也就是差別幀,P幀沒有完整畫面數據,只有與前一幀的畫面差別的數據)

P幀的預測與重構:P幀是以I幀為參考幀,在I幀中找出P幀“某點”的預測值和運動矢量,取預測差值和運動矢量一起傳送。在接收端根據運動矢量從I幀中找出P幀“某點”的預測值並與差值相加以得到P幀“某點”樣值,從而可得到完整的P幀。 

P幀特點: 
1.P幀是I幀後面相隔1~2幀的編碼幀; 
2.P幀採用運動補償的方法傳送它與前面的I或P幀的差值及運動矢量(預測誤差); 
3.解碼時必須將I幀中的預測值與預測誤差求和後才能重構完整的P幀圖像; 
4.P幀屬於前向預測的幀間編碼。它只參考前面最靠近它的I幀或P幀; 
5.P幀可以是其後面P幀的參考幀,也可以是其前後的B幀的參考幀; 
6.由於P幀是參考幀,它可能造成解碼錯誤的擴散; 
7.由於是差值傳送,P幀的壓縮比較高。 

B幀:雙向預測內插編碼幀。B幀是雙向差別幀,也就是B幀記錄的是本幀與前後幀的差別(具體比較複雜,有4種情況,但我這樣說簡單些),換言之,要解碼B幀,不僅要取得之前的緩存畫面,還要解碼之後的畫面,通過前後畫面的與本幀數據的疊加取得最終的畫面。B幀壓縮率高,但是解碼時CPU會比較累。 

B幀的預測與重構 B幀以前面的I或P幀和後面的P幀為參考幀,“找出”B幀“某點”的預測值和兩個運動矢量,並取預測差值和運動矢量傳送。接收端根據運動矢量在兩個參考幀中“找出(算出)”預測值並與差值求和,得到B幀“某點”樣值,從而可得到完整的B幀。 

B幀特點 
1.B幀是由前面的I或P幀和後面的P幀來進行預測的; 
2.B幀傳送的是它與前面的I或P幀和後面的P幀之間的預測誤差及運動矢量; 
3.B幀是雙向預測編碼幀; 
4.B幀壓縮比最高,因為它只反映丙參考幀間運動主體的變化情況,預測比較準確; 
5.B幀不是參考幀,不會造成解碼錯誤的擴散。 

注:I、B、P各幀是根據壓縮算法的需要,是人為定義的,它們都是實實在在的物理幀。一般來說,I幀的壓縮率是7(跟JPG差不多),P幀是20,B幀可以達到50。可見使用B幀能節省大量空間,節省 出來的空間可以用來保存多一些I幀,這樣在相同碼率下,可以提供更好的畫質。


--------------------------------
壓縮算法的說明
--------------------------------
h264的壓縮方法:
1.分組:把幾幀圖像分為一組(GOP,也就是一個序列),為防止運動變化,幀數不宜取多。
2.定義幀:將每組內各幀圖像定義為三種類型,即I幀、B幀和P幀; 
3.預測幀:以I幀做為基礎幀,以I幀預測P幀,再由I幀和P幀預測B幀; 
4.數據傳輸:最後將I幀數據與預測的差值信息進行存儲和傳輸。
        幀內(Intraframe)壓縮也稱為空間壓縮(Spatial compression)。當壓縮一幀圖像時,僅考慮本幀的數據而不考慮相鄰幀之間的冗餘信息,這實際上與靜態圖像壓縮類似。幀內一般採用有損壓縮算法,由於幀內壓縮是編碼一個完整的圖像,所以可以獨立的解碼、顯示。幀內壓縮一般達不到很高的壓縮,跟編碼jpeg差不多。
  
        幀間(Interframe)壓縮的原理是:相鄰幾幀的數據有很大的相關性,或者說前後兩幀信息變化很小的特點。也即連續的視頻其相鄰幀之間具有冗餘信息,根據這一特性,壓縮相鄰幀之間的冗餘量就可以進一步提高壓縮量,減小壓縮比。幀間壓縮也稱為時間壓縮(Temporal compression),它通過比較時間軸上不同幀之間的數據進行壓縮。幀間壓縮一般是無損的。幀差值(Frame differencing)算法是一種典型的時間壓縮法,它通過比較本幀與相鄰幀之間的差異,僅記錄本幀與其相鄰幀的差值,這樣可以大大減少數據量。

        順便說下有損(Lossy )壓縮和無損(Lossy less)壓縮。無損壓縮也即壓縮前和解壓縮後的數據完全一致。多數的無損壓縮都採用RLE行程編碼算法。有損壓縮意味著解壓縮後的數據與壓縮前的數據不一致。在壓縮的過程中要丟失一些人眼和人耳所不敏感的圖像或音頻信息,而且丟失的信息不可恢復。幾乎所有高壓縮的算法都採用有損壓縮,這樣才能達到低數據率的目標。丟失的數據率與壓縮比有關,壓縮比越小,丟失的數據越多,解壓縮後的效果一般越差。此外,某些有損壓縮算法採用多次重複壓縮的方式,這樣還會引起額外的數據丟失。

2015年3月12日 星期四

不應該在建構函數中呼叫虛擬函數(Virtual function)


程式執行到一個衍生物件並開始建構時, 它的基底物件會先被建構起來並產生其VTABLE. 如果衍生類別有重新定義某個虛擬函數, 則衍生物件的建構函數會在該衍生物件的;VTABLE中更新被重新定義虛擬函數之位址. 這就是你不應該在建構函數中呼叫虛擬函數的原因: 衍生物件中被重定義的虛擬函數之位址可能還沒有被放入/更改到衍生物件之VTABLE中. 你可能執行到舊的虛擬函數.

完整原文

Modern C++ in embedded systems Part 1 : Myth and Reality


Modern C++ in embedded systems Part 1 : Myth and Reality
by 

References
A reference in C++ is physically identical to a pointer. Only the syntax is different. References are safer than pointers because they can’t be null, they can’t be uninitialized, and they can’t be changed to point to something else. The closest thing to a reference in C is a const pointer. Note that this is not a pointer to a const value, but a pointer that can’t be modified. Listing 3 shows a C++ code fragment with a reference. 

     // C++ reference example
     void accumulate(int& i, int j) {
         i += j;
     }


Listing 3: C++ reference


2015年3月7日 星期六

[NTFS, Win7] Symbolic link














mklink:Creates a symbolic link.
適用平台:Windows Server 2008, Windows Vista、Windows 7 等以上版本

Syntax:

mklink [[/d] | [/h] | [/j]]

Parameters:

ParameterDescription
/dCreates a directory symbolic link. By default, mklink creates a file symbolic link.
/hCreates a hard link instead of a symbolic link.
/jCreates a Directory Junction.
Specifies the name of the symbolic link that is being created.
Specifies the path (relative or absolute) that the new symbolic link refers to.
/?Displays help at the command prompt.

Examples:
mklink /d C:\Users\eric_c_huang\Desktop\AAA C:\Document\ABC
在桌面上建立名為 AAA 的 symbolic link ,連結至 C:\Document  的 ABC 目錄…

建立 symbolic link 需要管理者權限,否則會出現「you do not have sufficient privilege to perform this operation」的錯誤訊息