# CCurl Note 產出: [iota-pow-in-c](https://github.com/chenweiii/iota-pow-in-c) ## Intorduction [ccurl (C port of the Curl library)](https://github.com/iotaledger/ccurl) 為 IOTA POW liarary. ## Installation ``` $ git clone https://github.com/iotaledger/ccurl $ cd ccurl $ git submodule update --init --recursive $ mkdir build && cd build && cmake .. && cmake --build . && cd .. ``` ## Usage * example: ``` ./build/bin/ccurl-cli 14 999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999QDPOHWNPSATIPICDZX9KAVIYPGUNXJETREPEAFASEFPYUFMHYZUNGMGDCXPGQJQDYCAYQLAQJTWCQHLCB999999999999999999999999999G99999999999999999999999999O9DAKXD99999999999999999999JLSCQZXU9XDFYWGUIHDUFFUIWVBFHPEKJCJLKEKTRQYUIFLYGOBFRLINNWLZLBXKDSDUNKIFVKQBRRXDB999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 ``` * output: (比較 input 的內容,你會發現多了 nonce 了!) ``` Getting platforms... Cannot get the number of OpenCL platforms available. E:-1 Thread Hashing... I: Starting search threads. I: Found threads. Returning. 999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999QDPOHWNPSATIPICDZX9KAVIYPGUNXJETREPEAFASEFPYUFMHYZUNGMGDCXPGQJQDYCAYQLAQJTWCQHLCB999999999999999999999999999G99999999999999999999999999O9DAKXD99999999999999999999JLSCQZXU9XDFYWGUIHDUFFUIWVBFHPEKJCJLKEKTRQYUIFLYGOBFRLINNWLZLBXKDSDUNKIFVKQBRRXDB9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999D99999999CV9B9999999999999 ``` 上述的 output 其實沒有辦法檢驗正確性,我們必須把它再 Hash 一次,再檢查字尾是否有 "9999" 所以可以更改 ```src/cli/ccurl.c``` 裡面的內容 ```clike= if (out != NULL) { char digest[HASH_LENGTH]; char *trits, *trytes; curl_t curl; init_curl(&curl); absorb(&curl, trits, 2673 * 3); squeeze(&curl, trytes, HASH_LENGTH); trytes = trytes_from_trits(digest, 0, HASH_LENGTH); fputs(trytes, stdout); } ``` 得到之 Output 為 ```JQS9WMZEWIVRCJHTDFIQAVKTAQJXGGKJLJYPXSEDBZVPRUC9O9LPFYPWBUMTPOEZTSEAGNXETPFXA9999```,驗證正確 ## Discussion * ccurl 主要計算 POW 的地方在於 [ccurl_pow](https://github.com/iotaledger/ccurl/blob/73f6346f78b21bc0c040a891bcd1c769bfba312d/src/lib/exports_cl.c#L69) * 在計算完 POW 之後,你可以看到函數利用一段 [memcpy](https://github.com/iotaledger/ccurl/blob/117e19cbfbdc37000d27452cfdbaf829608f9ee4/src/lib/exports_cl.c#L105) 把 nonce 寫進去 input trytes 中了,此時 POW 完成。 * 目前支援的實作為 Pure C & OpenCL ## 有關 PoW 的程式架構 * 直接使用 OpenCL 的實作 * 進入點為 ```ccurl_pow``` * 可以 concurrently 地被呼叫 * host 會開啟多條 thread (pthread),一條 thread 會負責啟動其中一個 Device 的 Command Queue * 在 ```pearlcldiver.c``` 裡可以看到 ```pearl_search()``` 宣告了與 Device 數量相同的 thread 數 * 一個 pdcl_node 代表著一個 src,裡面的結構 (PearCLDiver) 預先宣告了所有 Device 數量的 Context, Command Queue, ...etc 給不同的 Device 使用 * 見 ```claccess/clcontext.h``` ## 程式碼分析 * 一個 pdcl_node 代表著一道 Pow Task * 不同的 Pow Task,其 pdcl_node 會用 linked-list 連起來 :::info 但是該 linked-list 並沒有上鎖的機制預防 race condition ::: * defined in ```src/lib/exports_cl.c``` ```clike= typedef struct pdcl_node { PearCLDiver* pdcl; int initialized; int cl_available; struct pdcl_node* next; } pdcl_node_t; ``` * 其中的 PearCLDiver * defined in ```src/lib/pearcldiver.h``` ```clike= typedef struct { CLContext cl; PearlDiver pd; size_t num_groups; size_t loop_count; } PearCLDiver; ``` * 其中的 CLContext * defined in ```src/lib/claccess/clcontext.h``` * 為每一個 Device 都保留一份 cl_context, ... 等 ```clike= typedef struct { cl_uint num_devices; cl_device_id device[CLCONTEXT_MAX_DEVICES]; cl_command_queue clcmdq[CLCONTEXT_MAX_DEVICES]; cl_mem buffers[CLCONTEXT_MAX_DEVICES][MAX_BUFFERS]; cl_kernel clkernel[CLCONTEXT_MAX_DEVICES][MAX_KERNELS]; cl_program programs[CLCONTEXT_MAX_DEVICES]; cl_context clctx[CLCONTEXT_MAX_DEVICES]; cl_uint num_cores[CLCONTEXT_MAX_DEVICES]; size_t num_multiple[CLCONTEXT_MAX_DEVICES]; cl_ulong max_memory[CLCONTEXT_MAX_DEVICES]; KernelInfo kernel; } CLContext; ``` * 當 user 呼叫 ccurl_pow,便會新增一個 pdcl_node,並接上 linked-list;或是找到一個已經搜尋完的 pdcl_node 直接使用,免去初始化的 overhead * defined in ```src/lib/exports_cl.c``` * 其中的 ```pearcl_search``` 便是 Pow 的起點 ```clike= char* ccurl_pow(char* trytes, int minWeightMagnitude) { pdcl_node_t* pd_node = &base; ccurl_pow_node_init(pd_node); while (pd_node->pdcl->pd.status == PD_SEARCHING) { if (pd_node->next != NULL) { pd_node = pd_node->next; } } if (ccurl_pow_node_init(pd_node) == 0) { pearcl_search(pd_node->pdcl, &curl, offset, minWeightMagnitude); } } ``` * 在執行 ```pearcl_search``` 之前,有關於 cl_context 都已初始化,kernel 也已經填好,而 ```pearcl_search``` 便負責 create threads 分別 launch 不同 Device 上的 command queue * 一條 thread 負責 launch 一個 Device 的 command queue! * defined in ```src/lib/pearcldiver.c``` ```clike= PDCLThread* pdthreads = (PDCLThread*)malloc(numberOfThreads * sizeof(PDCLThread)); while (numberOfThreads-- > 0) { pdthreads[numberOfThreads] = (PDCLThread){.states = states, .curl = curl, .min_weight_magnitude = min_weight_magnitude, .index = numberOfThreads, .offset = offset, .pdcl = pdcl}; pthread_create(&tid[numberOfThreads], NULL, &pearcl_find, (void*)&(pdthreads[numberOfThreads])); } ``` * 而 ```pearcl_find``` 會負責將資料寫入 OpenCL memory buffer,並分別 launch 三個 Kernel ## TODO - [ ] 把剩下的 code 看完。 - [ ] 驗證 multi-thread POW!