Wednesday, September 25, 2019

從硬體觀點了解 memory barrier 的實作和效果

轉自
https://medium.com/fcamels-notes/%E5%BE%9E%E7%A1%AC%E9%AB%94%E8%A7%80%E9%BB%9E%E4%BA%86%E8%A7%A3-memry-barrier-%E7%9A%84%E5%AF%A6%E4%BD%9C%E5%92%8C%E6%95%88%E6%9E%9C-416ff0a64fc1

之前從軟體的角度寫過 memory barrier 的介紹《Memory Barriers: a Hardware View for Software Hackers》則是從硬體的角度了解硬體設計者的需求,以及 read/write memory barrier 如何運作。我只有讀完前五章,後面用我理解的方式摘要這篇文章。本文的圖示都是從該篇文章取出來的。
CPU 速度很快,main memory 讀寫速度很慢,所以要加上 cache 減少讀寫 memory 的次數,從《Latency Numbers Every Programmer Should Know 》得知存取 memory 的時間是 100 ns, L1 cache 是 0.5 ns,兩者差了 200 倍。
使用 cache 的時候,要確保各 CPU 有看到「一致的資料」 (注意重點放在 CPU 之間,不是 cache 和 memory 保持同步,這點細微的差異會影響到架構設計)。維護這點的協定統稱為 cache-coherence protocol。其中,MESI protocol 是一個基本版,從 MESI protocol 可以了解 CPU 之間如何維持看到一致的資料。

MESI Protocol

這篇文章有介紹 MESI protocol,不過個人覺得 Wikipedia 的介紹比較清楚一點,可以交互參照:
The letters in the acronym MESI represent four exclusive states that a cache line can be marked with (encoded using two additional bits):
Modified(M): The cache line is present only in the current cache, and is dirty — it has been modified(M state) from the value in main memory. The cache is required to write the data back to main memory at some time in the future, before permitting any other read of the (no longer valid) main memory state. The write-back changes the line to the Shared state(S).
Exclusive(E): The cache line is present only in the current cache, but is clean — it matches main memory. It may be changed to the Shared state at any time, in response to a read request. Alternatively, it may be changed to the Modified state when writing to it.
Shared(S): Indicates that this cache line may be stored in other caches of the machine and is clean — it matches the main memory. The line may be discarded (changed to the Invalid state) at any time.
Invalid(I): Indicates that this cache line is invalid (unused).
For any given pair of caches, the permitted states of a given cache line.
簡述一下四個狀態意思:
  • Modified (M): 只有該 cache line 裡有最新資料,比 main memory 裡的資料還新
  • Exclusive (E): 只有該 cache line 裡有最新資料,不過和 main memory 一致
  • Shared (S): 有兩個以上的 cache lines 有最新資料,和 main memory 一致
  • Invalid (I): cache line 內的資料已過時,不可使用
透過 MESI protocol,任何一個 CPU 要寫入資料前,都要先確保其它 CPU 已 invalid 同一位置的 cache 後 (希望寫入的 CPU 廣播 invalidate,其它 CPU 回 invalidate ack), 才能寫資料到自己的 cache,並在稍後補寫回 memory。
這個設計確保資料的一致性,不用擔心同一時間同一個位置的資料會有不同的值,但是代價是寫入 cache 的速度會有點慢,讓 CPU 閒置。
假設 CPU 0 打算寫入資料到位置 X,CPU 1 的 cache 有 X 的值。慢的原因如下:
  • CPU 0 要等 CPU 1 回 invalidate ack。
  • CPU 1 的 cache 可能太忙而拖慢了回覆時間 (比方同時從 cache 大量的讀寫資料,或是短時間收到大量 invalidate ack)。

Store Buffer 和 Invalidate Queue

針對上述問題,以下的方法可以縮短 CPU 0 閒置時間:
  • CPU 0 不等 invalidate ack:先寫入 store buffer,然後繼續作事。之後收到 invalidate ack 再更新 cache 的狀態。因為最新的資料可能存在 store buffer,CPU 讀資料的順序變成 store buffer → cache → memory。
  • CPU 1 立即回 invalidate ack:收到 invalidate 時,記錄到 invalidate queue 裡,先回 invalidate ack,稍後再處理 invalidate。
因為 store buffer 很小,store buffer 滿的時候,CPU 0 還是得等 invalidate ack,所以加上 invalidate queue,雙管齊下減少 CPU 0 等待時間。
擴展後的 cache 架構如下:
因為多了 store buffer 和 invalidate queue,cache 之間的資料就沒有完全一致了,該篇文章有詳細說明會產生問題的狀況,推薦一讀。這裡用我的方式簡述大概情況。

store buffer 的問題與 write barrier

int a = b = 0;
void foo(void) 
{ 
  a = 1; 
  b = 1;
}void bar(void)
{ 
  while (b == 0) continue; 
  assert(a == 1);
}
考慮 CPU 0 執行 foo(), CPU 1 執行 bar()。假設 cache 的狀態如下:
        a       b
------------------------
CPU 0:  Shared  Modified
CPU 1:  Shared  Invalid
CPU 0 步驟如下:
  1. 寫入 a 的值 (=1) 到 store buffer (但 cache 裡仍是 0)
  2. 廣播 “invalidate a”
  3. 改 b 的值。因為 b 的狀態已是 Modified,cache 的值更新成 1
接著 CPU 1 從 CPU 0 的 cache 讀到 b = 1,繼續執行 assert()。從自己的 cache 裡取值 (=0)。然後收到 CPU 0 送來 “invalidate a” 的訊息,但已太遲了。
問題出在 store buffer 破壞了 cache coherence,資料不再是同一時間只有一份值。於是 CPU 需要提供 write memory barrier,讓軟體有機會避免這個問題。
write memory barrier 確保之前在 store buffer 裡的資料會先更新到 cache,然後才能寫入 barrier 之後的資料到 cache。假設我們在 foo() 的 a=1 和 b=1 之間插一個 write memory barrier。文中介紹的實作方式如下:
  1. write memory barrier 先設 store buffer 裡的資料為 “marked” (即 a=1)
  2. 寫入 b 的時候,因為發現 store buffer 裡有 marked 的欄位,所以即使 b 已處於 Modified,仍需寫入 b=1 到 store buffer,不過狀態是 “unmarked”
  3. 待收到 a 的 invalidate ack 後,cache 中 a 的狀態改為 Modified,然後先寫入有 marked 欄位的值到 cache,再寫入 unmarked 欄位的值到 cache。
這樣其它 CPU 就會依序看到 a、b 更新的值了。

invalidate queue 的問題和 read memory barrier

用同樣的程式為例,假設 CPU 1 的 cache 裡 a 處於 Shared。CPU 0 已更新 a、b 到它的 cache,CPU 1 的 invalidate queue 裡有 "invalidate a”,但還沒處理。
這時 CPU 1 依序讀 b、a 的值,會從 CPU 0 的 cache 讀到 b=1,然後從自己的 cache 讀到 a=0 (因為還沒 invalidate a)。所以需要 read memory barrier 確保先清空 invalidate queue 再繼續讀資料。
若在 assert(a==1) 之前插入 read memory barrier,執行順序變成這樣:
  1. CPU 1 執行 read memory barrier 時會設 invalidate queue 裡的資料為 “marked”
  2. CPU 1 讀 cache 裡 a 的值時,發現 invalidate queue 裡有標記 a,於是會先執行 invalidate a 再繼續讀 a 的值
  3. 執行 invalidate a 後,就不會讀自己 cache 的值,而改從 CPU 0 的 cache 讀到最新的值,達到「依序讀 b、a 的值」的效果。

結論

硬體為了減少讀寫 memory 而有 cache。有 cache 就要確保 cache 之間的資料一致 (同一時間同一位置只有一個值)。但確保 cache 資料完全一致容易讓 CPU 閒置,於是有了 store buffer 和 invalidate queue 降少 CPU 閒置。代價是只保證 CPU 自己會讀到自己寫入的最新資料,但其它 CPU 不一定。
為了讓其它 CPU 有需要的時候也能讀到最新的資料,針對 store buffer 和 invalidate queue 的副作用設計了 write/read memory barrier。於是寫軟體的人在需要的時候可以用 memory barrier 確保關鍵的資料有依正確的順序更新 (沒保證更新的時間)。CPU 在多數情況下仍能避免閒置。
到此可以了解為什麼這兩種操作合在一起比較符合 CPU 架構:
  • 一個 thread 「先 write X 後執行 write memory barrier」
  • 另一個 thread 「先執行 read memory barrier 後 read X」
兩者合起來構成 happens-before relation。由此可以理解 Sequential-consistent 和硬體的運作方式差太多,會太常讓多個 CPU 閒置,無法發揮多 CPU 的效能。

相關文章

演算法與資料結構

演算法與資料結構


Thursday, August 08, 2019

Tuesday, March 07, 2017

TWD97 JGD2000


TWD97 / TM2 zone 121

http://georepository.com/crs_3826/TWD97-TM2-zone-121.html

JGD2000 / Japan Plane Rectangular CS VII
http://georepository.com/crs_2449/JGD2000-Japan-Plane-Rectangular-CS-VII.html

Tuesday, September 27, 2016

Python neural network




http://www.rightrelevance.com/search/articles/hero?article=1e1842881703838b6b9a738fb90d5135123ef161&query=python&taccount=pythonrr




http://www.pyimagesearch.com/2016/09/26/a-simple-neural-network-with-python-and-keras/

Thursday, June 16, 2016

Apache Mynewt RTOS for IoT Includes an Open Source Bluetooth 4.2 LE Stack for MCUs


http://www.cnx-software.com/2016/06/15/apache-mynewt-rtos-for-iot-includes-an-open-source-bluetooth-4-2-stack-for-mcus/

The Apache Software Foundation has recently released version 0.9 Apache Mynewt open source real-time operating systems for micro-controllers under… an Apache 2.0 license. The RTOS works on STMicro STM32 Cortex-M4, and Arduino Zero / M0 Cortex-M0 boards, but they’ve also implemented the  first open source Bluetooth Low Energy stack for MCUs, starting with support for Nordic Semi nRF52 Cortex-M4 and nRF51 Cortex-M1 evaluation boards, and acting as a replacement forNordic SoftDevice Bluetooth Smart / LE solution.
Apache_Mynewt_System_Block_DiagramThe operating system competes with ARM mbed, the Zephyr Project, and RIoT, but the foundation claims it is the only one that’s both community driven and permissively licensed (Apache 2.0) project in the embedded space.
The OS is modular and can be configured with a Go-like build and package management tool with components such as secure boot loader, flash file system and TLV storage mechanism, rich logging infrastructure, circular buffering schemes, and Bluetooth 4.2 Low Energy. WiFi, Thread, and Bluetooth 5 are also part of the roadmap, and support for Javascript and Python is currently being worked on.
You can find more information and/or get started with the project on Apache Mynewt microsite.

Wednesday, May 18, 2016

Android 应用签名提权方法

轉自:
http://hubeihuyanwei.blog.163.com/blog/static/28205284201321432453596/


使用android自带的签名工具signapk.jar 以及源码中的platform.x509.pem,platform.pk8 对apk进行重新签名。

   执行:java -jar signapk.jar  platform.x509.pem platform.pk8 old.apk new.apk 执行后new.apk即为签名后的文件。

   (注:执行命令时所有文件这里放在同一目录下,如果不在同一目录请修改路径)。

  文件platform.x509.pem和platform.pk8我们可以在源码的 build/target/product/security中找到。signapk.jar 可以编译build/tools/signapk/ 得到。

5.签名后就可以安装使用了

====================
platform.x509.pem和platform.pk8的用处

很多网友可能需要访问一些系统敏感的设置信息,如果没有Root权限如何解决呢? platform.x509.pem和platform.pk8可以让你获得系统权限,Android在系统账户安全中使用了Linux的ACL控制方式,通过在每个App中使用sharedUserId设置即可共享系统账户权限,比如android:sharedUserId="android.uid.system" 这样就是用了system这个uid了。

  platform.x509.pem和platform.pk8我们可以在platform/build/target/product/security中找到,如果你的固件使用的Android官方标准的key编译的,可以通过signapk.jar来使用这个系统key/cer来签名的你的apk。使用方法比较简单java -jar SignApk.jar platform.x509.pem platform.pk8 cwj.apk cwj_signed.apk 这行就代表,将cwj.apk签名,签名后的cwj_signed.apk就是拥有系统权限的apk了。如果网友找不到signapk.jar,Android123提示大家可以在/platform/build/tools/signapk/下编译即可。

  当然Android开发网提示如果部分开发者在编译系统时使用的并非GIT源码中的platform.x509.pem platform.pk8可能造成在该目标固件中无法正确安装,当然了这两个文件就是我们普通的key/cert而已,只是作为平台名称有些改变。


Tuesday, May 17, 2016

人生之不知所云

生命是很奇妙的東西
逆境與夢想都是有時都是生命的一部份
知道自己的夢與自己在此刻的角色
那麼便算是不虛此生了吧~~
---
如果發現人生的短暫
  就愈要使它更有深度
更加充實!

[debug] rr 全名是 record and replay

以下轉自:
https://m.facebook.com/story.php?story_fbid=10204658121093179&id=1840131181

今天突然想到我似乎沒發文推廣過 rr 這個神級的 debug 工具(又稱軟體工程師的時光機),這麼好用的東西不能只有我知道
rr 全名是 record and replay,只要你的程式跑在 Linux 上,可以用 gdb debug(例如 C/C++/Rust 寫的程式),都可以用 rr 把程式的執行結果錄下來,再反覆的用 rr 重播,並用 gdb debug。這能完全改寫你除錯程式的經驗,它有以下特色:
1. 在這個 record 中,記憶體位址是不變的,所以可以反覆用 gdb 去看程式資料的變化。你也不必怕 gdb 當掉,毀掉你辛苦重製的環境,而你在筆記本記的 memory address 都泡湯)
2. 因為你在 debug 錄下來的程式執行過程,所以你甚至可以「倒著」執行程式。 一般 gdb 的必用的指令如 step、continue,rr 都提供了的反向版的 reverse-step、reverse-continue。
以常見的 debug null pointer crash 為例,通常都是某個物件被某個不知道在哪的函式 F 放掉了,但你執行到程式 crash 時,不知名的 F 不知道在 crash 前多早就執行了。如果這個 crash 很難重製,程式又不是你寫的,你就只能慢慢熟悉程式,印 log,找出可以穩定重製的步驟…然後自求多福(超花時間)。
如果用了 rr,你就只要重製出 crash 一次,再 replay。等到程式 crash,設定個 watch point 在被設成 null 的變數,下 reverse-continue 倒著執行程式回去。馬上抓到兇手!多的時間就可以開始研究程式的邏輯了。
rr 在我 debug Firefox 這麼複雜的程式時真的幫我很多忙,一堆 ref-counted 的物件加上 event 飛來飛去,程式邏輯真的不會照你想的運作。
如果你開發的程式在 Linux 上,不妨試試。如果有老師在教學生用 gdb,也不妨也告訴學生有 rr 這個工具,讓學生的程式生涯輕鬆一點。

rr網站:
http://rr-project.org/

MQTT(一)簡介

轉自:
http://blog.maxkit.com.tw/2014/01/mqtt.html


前言

會知道MQTT協定,要先回憶起兩年前,當初想找找Android的Push Notification的解決方案,先是找到了當時GCM的前身C2DM,以為Google已經提供了此服務,測試了一下code也蠻容易上手的,結果發現到他有quota限制,不適合拿來當成產品,因此就放棄它,改找別的解決方案,最後找到了兩種不同的實作方式,一種透過XMPP協定來完成,另一種也就是今天要提到的,透過MQTT來完成。

所以MQTT是什麼?

MQTT的全名為 Message Queuing Telemetry Transport,為IBM和Eurotech共同製定出來的protocol,在MQTT的官網可以看到一開始它對MQTT的介紹:
MQTT is a machine-to-machine (M2M)/"Internet of Things" connectivity protocol. It was designed as an extremely lightweight publish/subscribe messaging transport.
簡單來說,它是為了物聯網而設計的protocol,並且它是透過publish/subscribe的方式來做訊息傳送。由於是為了物聯網而設計的協定,因此它所需要的網路頻寬是很低的,而所需要的硬體資源也是低的。

Publish/Subscribe:

在看MQTT之前,最好要先知道Publish/Subscribe的訊息傳送機制為何,這樣之後在看其協定時,才會更快上手。Publish/Subscribe有三種主要的組成元件,分別為Publisher、Subscriber以及Topic。

Publisher為訊息的來源,它會將訊息發送給Topic,而Subscriber向Topic註冊,表示他們想要接收此Topic的訊息;因此當有某個Publisher對Topic發送訊息時,只要是有對此Topic註冊的Subscriber,都會收到此則訊息。
它們的關係如下圖:


MQTT特性:

了解了Publish/Subscribe的機制之後,讓我們來看看MQTT有哪些特性:
  1. Publish/Subscribe的訊息傳送模式,來提供一對多的訊息分配。
  2. 使用TCP/IP來提供基本的網路連結。
  3. 三種訊息傳送服務的qualities:
    • "At most once",最多一次,訊息遺失或是重複發送的狀況可能會發生;這種quality適合應用在環境感測,不在意資料是否會遺失,因為下一次的資料取樣很快就會被published出來。
    • "At least once",至少一次,這種quality保證訊息會送達,只是可能會發生重複發送訊息的狀況。
    • "Exactly once",確定一次,確認訊息只會送到一次。這種quality適合用在計費系統,系統只要有重複收到資料、或是資料遺失狀況發生,就會造成系統錯誤。
  4. 由於他的header固定長度為2byte,因此可以減少封包傳送時的額外負載,並減少所需的網路頻寬。
  5. 當異常斷線發生時,會使用最後遺囑(Last Will and Testament)的機制,通知各個感興趣的client。

MQTT現況:

MQTT現階段並不是一個標準化的Protocol,還在持續改進中,目前為MQTT V3.1。不過IBM已於2013年已經將它交給OASIS進行標準化了,並且一直以來IBM對此協定採開放、免授權費的方式讓它能夠被散佈,因此相信不久的將來會成為一個主流的Protocol。

而目前支援MQTT的Client API,有Eclipse Phno Project有對MQTT client支援,其支援C、Java、Javascript、C++等等的語言,可說是支援度很高的Project。而目已經在應用MQTT的,最知名的應該就是Facebook Message App了吧,可以參考此篇文章文章

小結:

上面提到的,低頻寬、低硬體需求的特性,訊息傳遞為Publish/Subscribe的方式,正好可以用來實現Push Notification的機制,並且能達到手持裝置省電的需求,接下來會先從其Protocol開始了解,並用Client Api跑些範例來應用此Protocol。

參考:

MQTT v3.1 specification

Introducing AWS IoT

Introducing AWS IoT:
https://www.youtube.com/watch?v=N3-Az0OH5WM





Friday, April 01, 2016

Object-oriented design patterns in the kernel, part 1


Object-oriented design patterns in the kernel, part 1


https://lwn.net/Articles/444910/

https://lwn.net/Articles/446317/


共筆: http://hackfoldr.org/dykc/

Sunday, January 31, 2016

[Netflix] Linux Performance

http://www.brendangregg.com/linuxperf.html

Netflix 工程師分享