0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

利用NVIDIA CUDA 11.5實(shí)現(xiàn)128十進(jìn)制算法

星星科技指導(dǎo)員 ? 來源:NVIDIA ? 作者:NVIDIA ? 2022-04-11 09:16 ? 次閱讀

計(jì)算的歷史已經(jīng)證明,用計(jì)算機(jī)硬件實(shí)現(xiàn)的相對(duì)簡(jiǎn)單的算法所能實(shí)現(xiàn)的是無限的。但計(jì)算機(jī)用有限大小的數(shù)字表示的“真相”基本上是近似的。正如大衛(wèi)·戈德伯格所寫,“ 將無限多個(gè)實(shí)數(shù)壓縮成有限位數(shù)需要一個(gè)近似表示 。”浮點(diǎn)是實(shí)數(shù)最廣泛使用的表示形式,在許多處理器中都有實(shí)現(xiàn),包括 GPU 。它之所以受歡迎,是因?yàn)樗軌虼硪粋€(gè)大的動(dòng)態(tài)范圍的價(jià)值觀,并權(quán)衡范圍和精度。

不幸的是,浮點(diǎn)的靈活性和范圍可能會(huì)在某些應(yīng)用程序中造成麻煩,因?yàn)樵诠潭ǚ秶鷥?nèi)的精度更為重要:想想美元和美分。二進(jìn)制浮點(diǎn)數(shù)不能準(zhǔn)確地代表每一個(gè)十進(jìn)制值,它們的近似值和舍入可能會(huì)導(dǎo)致累積錯(cuò)誤,例如,在會(huì)計(jì)計(jì)算中可能是不可接受的。此外,添加非常大和非常小的浮點(diǎn)數(shù)可能會(huì)導(dǎo)致截?cái)噱e(cuò)誤。由于這些原因,許多貨幣和會(huì)計(jì)計(jì)算都是使用定點(diǎn)十進(jìn)制算法實(shí)現(xiàn)的,該算法存儲(chǔ)固定數(shù)量的小數(shù)位數(shù)。根據(jù)所需的范圍,定點(diǎn)算法可能需要更多的位。

NVIDIA GPU 不在硬件中實(shí)現(xiàn)定點(diǎn)算法,但 GPU 加速的軟件實(shí)現(xiàn)可能是高效的。事實(shí)上, RAPIDS cuDF 庫已經(jīng)提供了高效的 32 位和 64 位定點(diǎn)十進(jìn)制數(shù)和計(jì)算。但是 RAPIDS cuDF 和 GPU 加速的 Apache Spark 的一些用戶需要 128 位小數(shù)提供的更高范圍和精度,現(xiàn)在 NVIDIA CUDA 11.5 提供了對(duì) 128 位整數(shù)類型(int128)的預(yù)覽支持,這是實(shí)現(xiàn) 128 位十進(jìn)制算法所需的。

在本文中,在介紹 CUDA 新的 int128 支持后,我們將詳細(xì)介紹如何在其上實(shí)現(xiàn)十進(jìn)制定點(diǎn)算法。然后,我們將演示 RAPIDS cuDF 中的 128 位定點(diǎn)支持如何使關(guān)鍵的 Apache Spark 工作負(fù)載完全在 GPU 上運(yùn)行。

介紹 CUDA __int128

在 NVIDIA CUDA 11.5 中, NVCC 離線編譯器在主機(jī)編譯器支持的平臺(tái)上為有符號(hào)和無符號(hào)__int128數(shù)據(jù)類型添加了預(yù)覽支持。nvrtc JIT 編譯器還增加了對(duì) 128 位整數(shù)的支持,但需要一個(gè)命令行選項(xiàng)--device-int128來啟用這種支持。算術(shù)、邏輯和位運(yùn)算都支持 128 位整數(shù)。請(qǐng)注意, DWARF 調(diào)試對(duì) 128 位整數(shù)的支持目前還不可用,并將在后續(xù)的 CUDA 版本中提供。在 11.6 版本中, cuda gdb 和 Nsight Visual Studio Code Edition 增加了對(duì)檢查這種新變量類型的支持。

NVIDIA GPU 以 32 位的數(shù)量計(jì)算整數(shù),因此 128 位整數(shù)用四個(gè) 32 位無符號(hào)整數(shù)表示。加法、減法和乘法算法非常簡(jiǎn)單,使用內(nèi)置的 PTX addc / madc 指令處理多個(gè)精度值。除法和余數(shù)使用簡(jiǎn)單的 O ( n ^ 2 )除法算法實(shí)現(xiàn),類似于 Brent 和 Zimmermann 的書 現(xiàn)代計(jì)算機(jī)算法 中的算法 1.6 ,并進(jìn)行了一些優(yōu)化,以改進(jìn)商選擇步驟并最小化校正步驟。 128 位整數(shù)的一個(gè)令人振奮的用例是使用它們實(shí)現(xiàn)十進(jìn)制定點(diǎn)算法。的 21.12 版本中包含 128 位十進(jìn)制定點(diǎn)支持 RAPIDS libcudf .繼續(xù)閱讀,了解更多關(guān)于定點(diǎn)算法的信息,以及__int128如何用于實(shí)現(xiàn)高精度計(jì)算。

不動(dòng)點(diǎn)算法

定點(diǎn)數(shù)字通過存儲(chǔ)小數(shù)部分的固定位數(shù)來表示實(shí)數(shù)。定點(diǎn)數(shù)字也可用于“省略”整數(shù)值的低階數(shù)字(即,如果你想表示 1000 的倍數(shù),你可以使用一個(gè) 10 進(jìn)制的定點(diǎn)數(shù)字,其刻度等于 3 )。記住定點(diǎn)和浮點(diǎn)之間區(qū)別的一個(gè)簡(jiǎn)單方法是,對(duì)于定點(diǎn)數(shù)字,小數(shù)點(diǎn)是固定的,而在浮點(diǎn)數(shù)字中,小數(shù)點(diǎn)可以浮動(dòng)(移動(dòng))。

定點(diǎn)數(shù)字背后的基本思想是,即使所表示的值可以有小數(shù)位數(shù)(也就是 1.23 中的 0.23 ),實(shí)際上也可以將值存儲(chǔ)為整數(shù)。例如,為了表示 1.23 ,可以用scale = -2和值 123 構(gòu)造一個(gè)fixed_point數(shù)字。通過將數(shù)值乘以小數(shù)位數(shù),可以將這種表示轉(zhuǎn)換為浮點(diǎn)數(shù)。在我們的例子中, 1.23 是通過 123 (值)乘以 0.001 ( 10 (基數(shù))乘以 -2 (刻度)的冪)得到的。當(dāng)構(gòu)造一個(gè)定點(diǎn)數(shù)時(shí),會(huì)出現(xiàn)相反的情況,您可以“移位”該值,以便將其存儲(chǔ)為整數(shù)(如果使用的是小數(shù)點(diǎn) -2 ( 0.001 ( 10 (基數(shù))與 -2 (小數(shù)點(diǎn))的冪之比),則浮點(diǎn)數(shù)為 1.23 時(shí),您將除以 0.001 )。

請(qǐng)注意,定點(diǎn)表示不是唯一的,因?yàn)榭梢赃x擇多個(gè)比例。對(duì)于 1.23 的示例,可以使用小于 -2 的任何比例,例如 -3 或 -4 。唯一的區(qū)別是存儲(chǔ)在磁盤上的數(shù)字不同; 123 表示刻度 -2 , 1230 表示刻度 -3 , 12300 表示刻度 -4 。當(dāng)您知道您的用例只需要一組小數(shù)位時(shí),您應(yīng)該使用 least precise (又名最大)刻度來最大化可表示值的范圍。使用 -2 刻度時(shí),范圍約為 -2000 萬至+ 2000 萬(小數(shù)點(diǎn)后兩位),而使用 -3 刻度時(shí),范圍約為 -2 萬至+ 200 萬(小數(shù)點(diǎn)后三位)。如果你知道你是在為錢建模,而且不需要小數(shù)點(diǎn)后三位,那么 scale-2 是一個(gè)更好的選擇。

定點(diǎn)類型的另一個(gè)參數(shù)是 base 。在本文的例子中,以及在 RAPIDS cuDF 中,我們使用 10 進(jìn)制,或十進(jìn)制定點(diǎn)。十進(jìn)制定點(diǎn)是最容易考慮的,因?yàn)槲覀儗?duì)十進(jìn)制(以 10 為基數(shù))數(shù)字很熟悉。定點(diǎn)數(shù)的另一個(gè)常用基數(shù)是基數(shù) 2 ,也稱為二進(jìn)制定點(diǎn)。這僅僅意味著,不是將數(shù)值按 10 的冪移動(dòng),而是將數(shù)值按 2 的冪移動(dòng)。您可以在后面的“示例”部分中看到一些二進(jìn)制和十進(jìn)制定點(diǎn)值的示例。

定點(diǎn)與浮點(diǎn)

表 1 :浮點(diǎn)和定點(diǎn)的比較。

絕對(duì)誤差是實(shí)際值與其計(jì)算機(jī)表示(以定點(diǎn)或浮點(diǎn)表示)之間的差值。相對(duì)誤差是絕對(duì)誤差與代表值之比。

為了演示定點(diǎn)可以解決的浮點(diǎn)表示問題,讓我們看看浮點(diǎn)是如何表示的。浮點(diǎn)數(shù)不能完全代表所有值。例如,與值 1.1 最接近的 32 位浮點(diǎn)數(shù)為 1.10000002384185791016 ( 看浮子。讓我們想象一下 )。在執(zhí)行算術(shù)運(yùn)算時(shí),尾隨的“不精確”可能會(huì)導(dǎo)致錯(cuò)誤。例如, 1.1 + 1.1 的收益率為 2.2000000476837158231 。

圖 1 :浮點(diǎn) 1.1 的可視化。

相比之下,使用定點(diǎn)表示時(shí),使用整數(shù)存儲(chǔ) exact 值。為了使用比例等于 -1 的定點(diǎn)數(shù)字表示 1.1 ,存儲(chǔ)值 11 。算術(shù)運(yùn)算是在基礎(chǔ)整數(shù)上執(zhí)行的,因此將 1.1 + 1.1 作為定點(diǎn)數(shù)相加,只需將 11 + 11 相加,就可以得到 22 ,正好代表值 2.2

為什么定點(diǎn)運(yùn)算很重要?

如前一個(gè)例子所示,定點(diǎn)算法避免了浮點(diǎn)數(shù)固有的精度和舍入誤差,同時(shí)還提供了表示小數(shù)的能力。通過保持相對(duì)誤差恒定,浮點(diǎn)提供了更大的值范圍。然而,這意味著,當(dāng)添加非常大和非常小的數(shù)字時(shí),它可能會(huì)出現(xiàn)較大的絕對(duì)(截?cái)啵╁e(cuò)誤,并會(huì)遇到舍入錯(cuò)誤。固定點(diǎn)表示法總是有相同的 absolute 錯(cuò)誤,代價(jià)是能夠表示縮小的值范圍。如果您知道小數(shù)點(diǎn)/二進(jìn)制點(diǎn)后需要特定精度,則定點(diǎn)允許您在不截?cái)噙@些數(shù)字的情況下保持其精度,即使值增長(zhǎng)到范圍的極限。如果你需要更多的范圍,你必須添加更多的位。因此,小數(shù) 128 對(duì)一些用戶來說變得很重要。

表 2 :小數(shù)點(diǎn) 32 的范圍,小數(shù)點(diǎn)= 2 。

fixed_point編號(hào)有許多應(yīng)用程序和用例。您可以找到使用fixed_point數(shù)字 on Wikipedia 的實(shí)際應(yīng)用程序列表

fixed_point inRAPIDSlibcudf

概述

RAPIDS lib cuDF ` fixed _ point `類型的核心是一個(gè)簡(jiǎn)單的類模板。

template 
class fixed_point { Rep _value; scale_type _scale;
}

fixed_point類的模板是:

  • Rep:表示fixed_point數(shù)字(例如,使用的整數(shù)類型)
  • Rad:數(shù)字的Radix(例如,基數(shù) 2 或基數(shù) 10 )

decimal32decimal64類型分別使用int32_tint64_t作為 Rep ,并且都有Radix::BASE_10.。scale是一個(gè)強(qiáng)類型的運(yùn)行時(shí)變量(請(qǐng)參見下面的運(yùn)行時(shí)刻度和強(qiáng)類型小節(jié)等)。

fixed_point類型有幾個(gè)構(gòu)造函數(shù)(請(qǐng)參見下面的“構(gòu)造方法”小節(jié))、可轉(zhuǎn)換為整型和浮點(diǎn)型的顯式轉(zhuǎn)換運(yùn)算符,以及完整的運(yùn)算符(加法、減法等)。

規(guī)模的跡象

在大多數(shù) C ++定點(diǎn)實(shí)現(xiàn)(包括 RAPIDS LIbcUDF )中,negative scale指示小數(shù)位數(shù)。positive scale表示可表示的倍數(shù)(例如,如果scale = 2表示decimal32,則可以表示 100 的倍數(shù))。

auto const number_with_pos_scale = decimal32{1.2345, scale_type{-2}}; // 1.23
auto const number_with_neg_scale = decimal32{12345, scale_type{2}}; // 12300

建設(shè)者

libcudf中提供了以下(簡(jiǎn)化的)構(gòu)造函數(shù):

fixed_point(T const& value, scale_type const& scale)
fixed_point(scaled_integer s) // already "shifted" value
fixed_point(T const& value) // scale = 0
fixed_point() // scale = 0, value = 0

其中,Rep是有符號(hào)整數(shù)類型,T可以是整數(shù)類型或浮點(diǎn)數(shù)。

設(shè)計(jì)與動(dòng)機(jī)

libcudf 的fixed_point類型有許多設(shè)計(jì)目標(biāo)。這些措施包括:

  • 需要運(yùn)行時(shí)量表
  • 與潛在標(biāo)準(zhǔn) C ++固定點(diǎn)類型的一致性
  • 強(qiáng)類型

下面詳細(xì)介紹了這些設(shè)計(jì)動(dòng)機(jī)。

運(yùn)行時(shí)規(guī)模和第三方定點(diǎn)庫

在設(shè)計(jì)階段,我們研究了八個(gè)現(xiàn)有定點(diǎn) C ++庫。不使用第三方庫的主要原因是,所有現(xiàn)有的定點(diǎn)類型/庫都是以scale作為編譯時(shí)參數(shù)設(shè)計(jì)的。這不適用于 RAPIDSlibcudf,因?yàn)樗枰?scale 作為運(yùn)行時(shí)參數(shù)。

雖然RAPIDS?libcudf是一個(gè) C ++庫,可以在 C ++應(yīng)用程序中使用,它也是后端RAPIDS cuDF,這是一個(gè) Python 庫。 Python 是一種解釋(而非編譯,如 C ++)語言。此外, cuDF 必須能夠從其他數(shù)據(jù)源讀取或接收定點(diǎn)數(shù)據(jù)。這意味著我們不知道編譯時(shí)定點(diǎn)值的scale。因此,我們需要在fixed_pointRAPIDS 中輸入fixed_point類型,該類型具有運(yùn)行時(shí)刻度參數(shù)。

我們引用的主要庫是CNL,John McFarlane的組成數(shù)字庫,目前是[VZX97 ]向C++標(biāo)準(zhǔn)中添加定點(diǎn)類型的參考。我們的目標(biāo)是使 RAPIDSlibcudf fixed_point類型盡可能與潛在的標(biāo)準(zhǔn)化類型相似。下面是 RAPIDSlibcudf和CNL之間的一個(gè)簡(jiǎn)單比較。

CNL (Godbolt Link

using namespace cnl;
auto x = fixed_point{1.23};

RAPIDS libcudf

using namespace numeric;
auto x = fixed_point{1.23, scale_type{-2}};

或者:

using namespace numeric;
auto x = decimal32{1.23, scale_type{-2}};

這里需要注意的最重要的區(qū)別是,在 CNL 示例中,-2作為模板(又稱編譯時(shí)參數(shù)),而在 cuDF lib cuDF 示例中,scale_type{-2}作為運(yùn)行時(shí)參數(shù)。

強(qiáng)類型

fixed_point類型的設(shè)計(jì)中融入了強(qiáng)類型。這方面的兩個(gè)例子是:

RAPIDS lib cuDF 堅(jiān)持強(qiáng)類型最佳實(shí)踐和強(qiáng)類型API,因?yàn)閺?qiáng)類型提供了保護(hù)和表達(dá)能力。與強(qiáng)大的打字相比,我不會(huì)進(jìn)入較弱的兔子洞,但是如果你想了解更多關(guān)于它的信息,那么有很多很棒的資源,包括Jonathon Bocarra的VC++上的流暢的C++帖子。

添加對(duì)decimal128的支持

RAPIDSlibcudf21.12 將 CUDA 添加為受支持的fixed_point類型。這需要進(jìn)行一些更改,第一個(gè)是添加依賴于decimal12811.5 提供的__int128類型的decimal128類型別名。

using decimal32 = fixed_point;
using decimal64 = fixed_point;
using decimal128 = fixed_point<__int128_t, Radix::BASE_10>;

這需要進(jìn)行一些內(nèi)部更改,包括更新類型特征函數(shù)__int128_t對(duì)某些函數(shù)的專門化,以及添加支持,以便cudf::column_view和朋友使用decimal128。以下簡(jiǎn)單示例演示了 lib cuDF API 與decimal128的配合使用(注意,所有這些示例對(duì)decimal32decimal64的作用相同)。

例子

簡(jiǎn)單貨幣

一個(gè)簡(jiǎn)單的貨幣示例使用libcudf提供的decimal32類型,其刻度為 -2 ,正好代表 17.29 美元:

auto const money = decimal32{17.29, scale_type{-2}};

大數(shù)和小數(shù)之和

當(dāng)求大值和小值之和時(shí),定點(diǎn)非常有用。作為一個(gè)簡(jiǎn)單的玩具示例,下面的代碼將指數(shù) -2 到 9 的 10 的冪相加。

template 
auto sum_powers_of_10() { auto iota = std::views::iota(-2, 10); return std::transform_reduce( iota.begin(), iota.end(), T{}, std::plus{}, [](auto e) -> T { return std::pow(10, e); });
}

比較 32 位浮點(diǎn)和十進(jìn)制定點(diǎn)可以得出以下結(jié)果:

sum_powers_of_10(); // 1111111168.000000
sum_powers_of_10(); // 1111111111.11

其中decimal_type是 32 位的 10 進(jìn)制定點(diǎn)類型。使用 Godbolthere上的 CNL 庫可以看到一個(gè)例子。

避免浮點(diǎn)舍入問題

下面是一段代碼(見Godbolt中),舉例說明浮點(diǎn)值遇到問題(在 C ++中):

std::cout << std::roundf(256.49999) << '
'; // prints 257

RAPIDS lib cuDF 中的等效代碼不會(huì)有相同的問題(請(qǐng)參見Github上的內(nèi)容):

auto col = // decimal32 column with scale -5 and value 256.49999
auto result = cudf::round(input); // result is 256

256.4999 的值不能用 32 位二進(jìn)制浮點(diǎn)表示,因此在調(diào)用 std :: roundf 函數(shù)之前,將其舍入到 256.5 。使用定點(diǎn)表示法可以避免這個(gè)問題,因?yàn)?256.4999 可以用任何具有五個(gè)或五個(gè)以上精度分?jǐn)?shù)值的 10 進(jìn)制(十進(jìn)制)類型來表示。

二進(jìn)制與十進(jìn)制定點(diǎn)

// Decimal Fixed Point
using decimal32 = fixed_point;
auto const a = decimal32{17.29, scale_type{-2}}; // 17.29
auto const b = decimal32{4.2, scale_type{ 0}}; // 4
auto const c = decimal32{1729, scale_type{ 2}}; // 1700 // Binary Fixed Point
using binary32 = fixed_point;
auto const x = binary{17.29, scale_type{-2}}; // 17.25
auto const y = binary{4.2, scale_type{ 0}}; // 4
auto const z = binary{1729, scale_type{ 2}}; // 1728

小數(shù) 128

// Multiplying two decimal128 numbers
auto const x = decimal128{1.1, scale_type{-1});
auto const y = decimal128{2.2, scale_type{-1}};
auto const z = x * y; // 2.42 with scale equal to -2 // Adding two decimal128 numbers
auto const x = decimal128{1.1, scale_type{-1});
auto const y = decimal128{2.2, scale_type{-1}};
auto const z = x * y; // 3.3 with scale equal to -1 

DecimalType和 RAPIDS Spark

Apache Spark SQL 中的 DecimalType 是一種可以表示 Java BigDecimal 值的數(shù)據(jù)類型。對(duì)財(cái)務(wù)數(shù)據(jù)進(jìn)行操作的 SQL 查詢大量使用十進(jìn)制類型。與定點(diǎn)十進(jìn)制數(shù)的 RAPIDS lib cuDF 實(shí)現(xiàn)不同, Spark 中的 DecimalType 可能的最大精度限制為 38 位。小數(shù)點(diǎn)后的位數(shù)也被限制在 38 。這個(gè)定義是 C ++刻度的否定。例如,像 0.12345 這樣的十進(jìn)制值在 Spark 中的刻度為 5 ,但在 libcudf 中的刻度為 -5 。

Spark 嚴(yán)格遵循 Apache Hive 操作精度計(jì)算規(guī)范,并為用戶提供配置十進(jìn)制操作精度損失的選項(xiàng)。 Spark SQL 在執(zhí)行聚合、窗口、強(qiáng)制轉(zhuǎn)換等操作時(shí)積極提高結(jié)果列的精度。這種行為本身就是使小數(shù) 128 與現(xiàn)實(shí)世界的查詢極其相關(guān)的原因,它回答了一個(gè)問題:“為什么我們需要支持高精度的小數(shù)列?”??紤]下面的例子,特別是哈希骨灰,它有一個(gè)乘法表達(dá)式,涉及一個(gè)十進(jìn)制 64 列,價(jià)格,和一個(gè)非十進(jìn)制列,數(shù)量。 Spark 首先將非十進(jìn)制列強(qiáng)制轉(zhuǎn)換為適當(dāng)?shù)氖M(jìn)制列。然后確定結(jié)果精度,該精度大于輸入精度。因此,即使涉及小數(shù) 64 個(gè)輸入,結(jié)果精度也是小數(shù) 128 的情況也很常見。

scala> val queryDfGpu = readPar.agg(sum('price*'quantity))
queryDfGpu1: org.apache.spark.sql.DataFrame = [sum((price * quantity)): decimal(32,2)] scala> queryDfGpu.explain
== Physical Plan ==
*(2) HashAggregate(keys=[], functions=[sum(CheckOverflow((promote_precision(cast(price#19 as decimal(12,2))) * promote_precision(cast(cast(quantity#20 as decimal(10,0)) as decimal(12,2)))), DecimalType(22,2), true))])
+- Exchange SinglePartition, true, [id=#429] +- *(1) HashAggregate(keys=[], functions=[partial_sum(CheckOverflow((promote_precision(cast(price#19 as decimal(12,2))) * promote_precision(cast(cast(quantity#20 as decimal(10,0)) as decimal(12,2)))), DecimalType(22,2), true))]) +- *(1) ColumnarToRow +- FileScan parquet [price#19,quantity#20] Batched: true,DataFilters: [], Format: Parquet, Location: InMemoryFileIndex[file:/tmp/dec_walmart.parquet], PartitionFilters: [], PushedFilters: [], ReadSchema: struct

隨著在 lib cuDF 中引入了新的小數(shù) 128 數(shù)據(jù)類型, Spark 的 RAPIDS 插件能夠利用更高的精度,并將計(jì)算保持在 GPU 上,而之前需要返回到 CPU 上。

作為一個(gè)例子,讓我們來看一個(gè)在以下模式下運(yùn)行的簡(jiǎn)單查詢。

{ id : IntegerType // Unique ID prodName : StringType // Product name will be used to aggregate / partition price	: DecimalType(11,2) // Decimal64 quantity : IntegerType // Quantity of product }

此查詢計(jì)算 totalCost 上的無界窗口,即總和(價(jià)格*數(shù)量)。然后,它會(huì)在排序后由 prodName 對(duì)結(jié)果進(jìn)行分組,并返回最小總成本。

// Run window operation
val byProdName = Window.partitionBy('prodName)
val queryDfGpu = readPar.withColumn( "totalCost", sum('price*'quantity) over byProdName).sort( "prodName").groupBy( "prodName").min( "totalCost")

RAPIDS Spark 插件設(shè)置為僅當(dāng)所有表達(dá)式都可以在 GPU 上計(jì)算時(shí),才在 GPU 上運(yùn)行運(yùn)算符。讓我們先看看下面這個(gè)查詢的物理計(jì)劃,不支持小數(shù) 128 。)

如果不支持十進(jìn)制 128 ,每個(gè)運(yùn)算符都會(huì)返回 CPU ,因?yàn)闊o法支持包含十進(jìn)制 128 類型的子表達(dá)式。因此,包含 exec 或父表達(dá)式的表達(dá)式也不會(huì)在 GPU 上執(zhí)行,以避免低效的行到列和列到行轉(zhuǎn)換。

== Physical Plan ==
*(3) HashAggregate(keys=[prodName#18], functions=[min(totalCost#66)])
+- *(3) HashAggregate(keys=[prodName#18], functions=[partial_min(totalCost#66)]) +- *(3) Project [prodName#18, totalCost#66] +- Window [sum(_w0#67) windowspecdefinition(prodName#18, specifiedwindowframe(RowFrame, unboundedpreceding$(), unboundedfollowing$())) AS totalCost#66], [prodName#18] +- *(2) Sort [prodName#18 ASC NULLS FIRST], false, 0 +- Exchange hashpartitioning(prodName#18, 1), true, [id=#169] +- *(1) Project [prodName#18, CheckOverflow((promote_precision(cast(price#19 as decimal(12,2))) * promote_precision(cast(cast(quantity#20 as decimal(10,0)) as decimal(12,2)))), DecimalType(22,2), true) AS _w0#67] +- *(1) ColumnarToRow +- FileScan parquet [prodName#18,price#19,quantity#20] Batched: true, DataFilters: [], Format: Parquet, Location: InMemoryFileIndex[file:/tmp/dec_walmart.parquet], PartitionFilters: [], PushedFilters: [], ReadSchema: struct

啟用小數(shù) 128 支持后的查詢計(jì)劃顯示,所有操作現(xiàn)在都可以在 GPU 上運(yùn)行。由于沒有 ColumnarToRow 和 RowToColumnar 轉(zhuǎn)換(在查詢中顯示為 collect 操作),因此通過在 GPU 上運(yùn)行整個(gè)查詢,可以獲得更好的性能。

== Physical Plan ==
GpuColumnarToRow false
+- GpuHashAggregate(keys=[prodName#18], functions=[gpumin(totalCost#31)]),
filters=ArrayBuffer(None)) +- GpuHashAggregate(keys=[prodName#18], functions=[partial_gpumin(totalCost#31)]), filters=ArrayBuffer(None)) +- GpuProject [prodName#18, totalCost#31] +- GpuWindow [prodName#18, _w0#32, gpusum(_w0#32, DecimalType(32,2)) gpuwindowspecdefinition(prodName#18, gpuspecifiedwindowframe(RowFrame, gpuspecialframeboundary(unboundedpreceding$()), gpuspecialframeboundary(unboundedfollowing$()))) AS totalCost#31], [prodName#18] +- GpuCoalesceBatches batchedbykey(prodName#18 ASC NULLS FIRST) +- GpuSort [prodName#18 ASC NULLS FIRST], false, com.nvidia.spark.rapids.OutOfCoreSort$@3204b591 +- GpuShuffleCoalesce 2147483647 +- GpuColumnarExchange gpuhashpartitioning(prodName#18, 1), true, [id=#57] +- GpuProject [prodName#18, gpucheckoverflow((gpupromoteprecision(cast(price#19 as decimal(12,2))) * gpupromoteprecision(cast(cast(quantity#20 as decimal(10,0)) as decimal(12,2)))), DecimalType(22,2), true) AS _w0#32] +- GpuFileGpuScan parquet [prodName#18,price#19,quantity#20] Batched: true, DataFilters: [], Format: Parquet, Location: InMemoryFileIndex[file:/tmp/dec_walmart.parquet], PartitionFilters: [], PushedFilters: [], ReadSchema: struct

對(duì)于乘法運(yùn)算,數(shù)量列轉(zhuǎn)換為小數(shù) 64 (精度= 10 ),價(jià)格列(已為小數(shù) 64 類型)轉(zhuǎn)換為精度 12 ,使兩列的類型相同。結(jié)果列的大小調(diào)整為精度 22 ,這是小數(shù) 128 類型,因?yàn)榫却笥?18 。這顯示在上面計(jì)劃的 GpuProject 節(jié)點(diǎn)中。

對(duì) sum ()的窗口操作也將精度進(jìn)一步提升到 32 。

我們使用 NVIDIA 決策支持( NDS )來衡量加速比, NDS 是 Spark 客戶和提供商經(jīng)常使用的 TPC-DS 數(shù)據(jù)科學(xué)基準(zhǔn)的一種改編。 NDS 包含與行業(yè)標(biāo)準(zhǔn)基準(zhǔn)相同的 100 多個(gè) SQL 查詢,但修改了數(shù)據(jù)集生成和執(zhí)行腳本的部分。? NDS 的結(jié)果與 TPC-DS 不可比。

NDS 查詢子集的初步運(yùn)行表明,由于支持小數(shù) 128 ,性能顯著提高,如下圖所示。它們?cè)诎藗€(gè)節(jié)點(diǎn)組成的集群上運(yùn)行,每個(gè)節(jié)點(diǎn)有一個(gè) A100 GPU 和 1024 CPU 內(nèi)核,在 Spark 3.1.1 上運(yùn)行 16 個(gè)內(nèi)核的執(zhí)行器。每個(gè)執(zhí)行器在內(nèi)存中使用 240GiB 。這些查詢顯示了接近 8 倍的出色加速,這可以歸因于以前的操作回到了現(xiàn)在在 GPU 上運(yùn)行的 CPU ,從而避免了行到列和列到行的轉(zhuǎn)換以及其他相關(guān)的開銷。所有 NDS 查詢的端到端運(yùn)行時(shí)間平均提高了 2 倍。這(希望)只是一個(gè)開始!

Performance evaluation of a subset of NDS queries.Performance evaluation of a subset of NDS queries.圖 2 :NDS 查詢子集的性能評(píng)估.

隨著 Spark Spark 插件的 21.12 版本發(fā)布,大多數(shù)操作員都可以使用十進(jìn)制 128 支持。需要對(duì)溢出條件進(jìn)行一些特殊處理,以保持 CPU 和 GPU 之間的結(jié)果兼容性。這項(xiàng)工作的最終目標(biāo)是通過 RAPIDS for Spark 插件,讓零售和金融查詢充分受益于 GPU 的加速。

總結(jié)

RAPIDS libcudf 中的固定點(diǎn)類型、 DecimalType 的添加以及 Spark 的 RAPIDS 插件的 decimal128 支持,使得以前只有在 CPU 上才可能在 GPU 上運(yùn)行的激動(dòng)人心的用例成為可能。

關(guān)于作者

Conor Hoekstra 是 NVIDIA 的高級(jí)圖書館軟件工程師,在 RAPIDS 團(tuán)隊(duì)工作。他對(duì)編程語言、算法和漂亮的代碼非常熱衷。他是編程語言虛擬 Meetup 的創(chuàng)始人和組織者,他有一個(gè) YouTube 頻道,他是兩個(gè)播客的主持人:算法+數(shù)據(jù)結(jié)構(gòu)=程序和 ArrayCast ??导{還是 CPPNNorth 會(huì)議的項(xiàng)目主席,也是一位熱心的會(huì)議發(fā)言人。

Kuhu Shukla 是 NVIDIA Spark- GPU 團(tuán)隊(duì)的高級(jí)軟件工程師。在此之前,她是雅虎 Hadoop 核心團(tuán)隊(duì)的成員!在伊利諾伊州香檳市的 Apache Tez 、 Thread 和 HDFS 等大數(shù)據(jù)平臺(tái)上工作。她是 Apache Tez 項(xiàng)目的 PMC 。她在北卡羅來納州立大學(xué)獲得了計(jì)算機(jī)科學(xué)碩士學(xué)位。

Mark Harris 是 NVIDIA 杰出的工程師,致力于 RAPIDS 。 Mark 擁有超過 20 年的 GPUs 軟件開發(fā)經(jīng)驗(yàn),從圖形和游戲到基于物理的模擬,到并行算法和高性能計(jì)算。當(dāng)他還是北卡羅來納大學(xué)的博士生時(shí),他意識(shí)到了一種新生的趨勢(shì),并為此創(chuàng)造了一個(gè)名字: GPGPU (圖形處理單元上的通用計(jì)算)。

審核編輯:郭婷

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • NVIDIA
    +關(guān)注

    關(guān)注

    14

    文章

    5109

    瀏覽量

    104519
  • gpu
    gpu
    +關(guān)注

    關(guān)注

    28

    文章

    4832

    瀏覽量

    129795
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1645

    瀏覽量

    49472
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    74HC390;74HCT390雙十進(jìn)制波紋計(jì)數(shù)器規(guī)格書

    電子發(fā)燒友網(wǎng)站提供《74HC390;74HCT390雙十進(jìn)制波紋計(jì)數(shù)器規(guī)格書.pdf》資料免費(fèi)下載
    發(fā)表于 02-09 15:16 ?0次下載
    74HC390;74HCT390雙<b class='flag-5'>十進(jìn)制</b>波紋計(jì)數(shù)器規(guī)格書

    74HC42 BCD至十進(jìn)制解碼器規(guī)格書

    電子發(fā)燒友網(wǎng)站提供《74HC42 BCD至十進(jìn)制解碼器規(guī)格書.pdf》資料免費(fèi)下載
    發(fā)表于 02-08 15:23 ?0次下載
    74HC42 BCD至<b class='flag-5'>十進(jìn)制</b>解碼器規(guī)格書

    bcd與十進(jìn)制之間的關(guān)系

    BCD(Binary-Coded Decimal)即二進(jìn)制編碼的十進(jìn)制數(shù),是一種用二進(jìn)制來表示十進(jìn)制數(shù)的編碼方式。以下是BCD與十進(jìn)制之間關(guān)
    的頭像 發(fā)表于 12-20 17:15 ?1568次閱讀

    bcd編碼的應(yīng)用 bcd與二進(jìn)制的區(qū)別

    BCD(Binary-Coded Decimal)編碼是一種二進(jìn)制編碼形式,用于表示十進(jìn)制數(shù)字。它將每個(gè)十進(jìn)制數(shù)字(0-9)直接編碼為一個(gè)四位二進(jìn)制數(shù)。BCD編碼的主要優(yōu)點(diǎn)是易于閱讀和
    的頭像 發(fā)表于 12-20 17:11 ?1862次閱讀

    Tlv320AIc23B配置時(shí),采用十六進(jìn)制,可以采用十進(jìn)制嗎?

    Tlv320AIc23B配置時(shí),采用十六進(jìn)制,可以采用十進(jìn)制嗎? 2初始化完成后,還可以單獨(dú)修改某一項(xiàng)配置嗎?還是要全部更新? void ancRenewINCodecRegs(uint16
    發(fā)表于 11-05 07:05

    矩陣4x4個(gè)按鍵,如何把識(shí)別結(jié)果按編號(hào)01-16(十進(jìn)制)顯示在兩個(gè)七段數(shù)碼管上?

    矩陣4x4個(gè)按鍵,并把識(shí)別結(jié)果按編號(hào)01-16(十進(jìn)制)顯示在兩個(gè)七段數(shù)碼管上,按鍵按下時(shí)顯示,不按時(shí)消失編號(hào)消失。 2.為了更加實(shí)用,要求加上去抖動(dòng)電路模塊
    發(fā)表于 10-31 20:43

    十進(jìn)制數(shù)據(jù)轉(zhuǎn)十六進(jìn)制字符_轉(zhuǎn)ASCII碼

    十進(jìn)制數(shù)據(jù)轉(zhuǎn)十六進(jìn)制字符_轉(zhuǎn)ASCII碼
    發(fā)表于 09-18 10:17 ?1次下載

    進(jìn)制處理中的一些技巧

    在二進(jìn)制十進(jìn)制的處理中,有時(shí)候一些小技巧是很有用的。 1、把十進(jìn)制數(shù)轉(zhuǎn)換成二進(jìn)制數(shù) (1)在MATLAB中有一個(gè)函數(shù)dec2bin,可以把正整數(shù)轉(zhuǎn)換為2
    的頭像 發(fā)表于 07-05 11:51 ?679次閱讀

    十進(jìn)制和4位二進(jìn)制計(jì)數(shù)器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《十進(jìn)制和4位二進(jìn)制計(jì)數(shù)器數(shù)據(jù)表.pdf》資料免費(fèi)下載
    發(fā)表于 05-31 09:32 ?1次下載
    <b class='flag-5'>十進(jìn)制</b>和4位二<b class='flag-5'>進(jìn)制</b>計(jì)數(shù)器數(shù)據(jù)表

    NVIDIA 通過 CUDA-Q 平臺(tái)為全球各地的量子計(jì)算中心提供加速

    —— NVIDIA 于今日宣布將通過開源的 NVIDIA CUDA-Q? 量子計(jì)算平臺(tái),助力全球各地的國(guó)家級(jí)超算中心加快量子計(jì)算的研究發(fā)展。 ? 德國(guó)、日本和波蘭的超算中心將使用該平臺(tái)來賦能他們由
    發(fā)表于 05-13 15:21 ?256次閱讀
    <b class='flag-5'>NVIDIA</b> 通過 <b class='flag-5'>CUDA</b>-Q 平臺(tái)為全球各地的量子計(jì)算中心提供加速

    雙4位十進(jìn)制和二進(jìn)制計(jì)數(shù)器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《雙4位十進(jìn)制和二進(jìn)制計(jì)數(shù)器數(shù)據(jù)表.pdf》資料免費(fèi)下載
    發(fā)表于 05-13 11:12 ?0次下載
    雙4位<b class='flag-5'>十進(jìn)制</b>和二<b class='flag-5'>進(jìn)制</b>計(jì)數(shù)器數(shù)據(jù)表

    同步4位十進(jìn)制和二進(jìn)制計(jì)數(shù)器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《同步4位十進(jìn)制和二進(jìn)制計(jì)數(shù)器數(shù)據(jù)表.pdf》資料免費(fèi)下載
    發(fā)表于 05-09 11:29 ?3次下載
    同步4位<b class='flag-5'>十進(jìn)制</b>和二<b class='flag-5'>進(jìn)制</b>計(jì)數(shù)器數(shù)據(jù)表

    CD74HC390、CDx4HCT390 高速 CMOS 邏輯雙路十進(jìn)制紋波計(jì)數(shù)器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《CD74HC390、CDx4HCT390 高速 CMOS 邏輯雙路十進(jìn)制紋波計(jì)數(shù)器數(shù)據(jù)表.pdf》資料免費(fèi)下載
    發(fā)表于 04-29 10:12 ?0次下載
    CD74HC390、CDx4HCT390 高速 CMOS 邏輯雙路<b class='flag-5'>十進(jìn)制</b>紋波計(jì)數(shù)器數(shù)據(jù)表

    使用EDIT_SetDecMode()函數(shù)設(shè)置十進(jìn)制編輯后變成了一個(gè)黑塊的原因?

    使用了EDIT_SetDecMode()函數(shù)設(shè)置十進(jìn)制編輯后,就變成這樣;但是在電腦上仿真界面的時(shí)候,數(shù)字和背景是會(huì)自動(dòng)反色的,但下載到單片機(jī)上就是一個(gè)黑色塊。請(qǐng)問會(huì)是什么原因?
    發(fā)表于 04-12 06:12

    BCD碼在PLC中的應(yīng)用與含義

    BCD是英文"Binary-Coded Decimal"的縮寫,直譯的意思是“二進(jìn)制編碼的十進(jìn)制數(shù)”,這種編碼的數(shù)制本質(zhì)上是十進(jìn)制。BCD碼用4個(gè)二進(jìn)制數(shù)表示一個(gè)
    發(fā)表于 03-21 11:17 ?3556次閱讀
    BCD碼在PLC中的應(yīng)用與含義