專利名稱:共同映射通信算子的制作方法
技術(shù)領(lǐng)域:
本申請涉及共同映射(co-map)通信算子。
背景技術(shù):
計算機系統(tǒng)通常包括一個或多個通用處理器(例如,中央處理器(CPU))以及一個或多個專用數(shù)據(jù)并行計算節(jié)點(例如,圖形處理單元(GPU)或CPU中的單指令多數(shù)據(jù)(SIMD)執(zhí)行單元)。通用處理器通常在計算機系統(tǒng)上執(zhí)行通用處理,而數(shù)據(jù)并行計算節(jié)點通常在計算機系統(tǒng)上執(zhí)行數(shù)據(jù)并行處理(例如圖形處理)。通用處理器通常具有實現(xiàn)數(shù)據(jù)并行算法的能力,但是在沒有在數(shù)據(jù)并行計算節(jié)點中發(fā)現(xiàn)的優(yōu)化的硬件資源的情況下這樣做。結(jié)果,通用處理器在執(zhí)行數(shù)據(jù)并行算法時可能比數(shù)據(jù)并行計算節(jié)點低效得多。 數(shù)據(jù)并行計算節(jié)點傳統(tǒng)地在計算機系統(tǒng)上執(zhí)行程序方面扮演通用處理器的輔助角色。隨著為數(shù)據(jù)并行算法優(yōu)化的硬件的角色由于數(shù)據(jù)并行計算節(jié)點處理能力的增強而增力口,增強程序員對數(shù)據(jù)并行計算節(jié)點進行編程的能力并使對數(shù)據(jù)并行計算節(jié)點進行編程變得更為容易可能是合乎需要的。數(shù)據(jù)并行算法經(jīng)常在較大的計算空間上操作。計算空間一般包括某種形式的索引來容許訪問個別的數(shù)據(jù)元素并在其上進行操作。然而,有時數(shù)據(jù)并行算法可通過在計算空間的索引結(jié)構(gòu)上操作而不是在數(shù)據(jù)元素上操作而產(chǎn)生期望的結(jié)果。
發(fā)明內(nèi)容
提供本發(fā)明內(nèi)容以便以簡化的形式介紹將在以下的具體實施方式
中進一步描述的一些概念。本概述并不旨在標識所要求保護主題的關(guān)鍵特征或必要特征,也不旨在用于限制所要求保護主題的范圍。高級編程語言提供了根據(jù)函數(shù)將輸入可索引的類型映射到輸出可索引類型的共同映射的通信算子。該函數(shù)將對應(yīng)于輸出可索引類型的索引空間映射到對應(yīng)于輸入可索引類型的索引空間。通過這樣做,共同映射的通信算子將索引空間上的函數(shù)提升到可索引類型上的函數(shù)以容許與其他通信算子的可組成性。
包括附圖來提供了對各實施例的進一步理解,且這些附圖被合并在本發(fā)明書內(nèi)并構(gòu)成其一部分。附圖示出各實施例,并且與說明書一起用于解釋本發(fā)明的原理。其他實施例和各實施例的許多預(yù)期優(yōu)點將隨著參考下面的詳細描述進行更好的理解而得到認識。附圖的元素不一定相對于彼此而縮放。相同的附圖標記指代對應(yīng)的類似部分。圖I是示出具有共同映射通信算子的代碼的實施例的計算機代碼圖。圖2是示出了將共同映射通信算子應(yīng)用到輸入可索引類型的實施例的框圖。圖3A-3C是示出使用共同映射的通信算子的示例的框圖。圖4是示出被配置成編譯并執(zhí)行包括共同映射通信算子的數(shù)據(jù)并行代碼的計算機系統(tǒng)的實施例的框圖。
具體實施例方式在以下具體實施例中,對附圖進行了參考,附圖構(gòu)成了實施例的一部分且在其中作為示例示出了可在其中實踐本發(fā)明的各特定實施例。就此,諸如“頂部”、“底部”、“前方”、“后方”、“前導(dǎo)”、“尾部”等的方向性術(shù)語參考正在描述的附圖的方向來使用。因為實施例的各組件可位于多個不同的方向,所以方向性術(shù)語出于說明的目的來使用而不是限制。可以理解,可以使用其它實施例并且可以做出結(jié)構(gòu)上或邏輯上的改變而不背離本發(fā)明的范圍。因此,以下詳細描述并不旨在限制,并且本發(fā)明的范圍由所附權(quán)利要求來限定。應(yīng)該理解,此處描述的各示例性實施例的特征可相互組合,除非另外具體注明。圖I是示出具有共同映射通信算子12的代碼10的實施例的計算機代碼圖。當(dāng)被編譯和執(zhí)行的時候,共同映射通信算子12根據(jù)函數(shù)13將輸入可映射類型14映射到輸出可映射類型18 (下文中定義)。函數(shù)13將對應(yīng)于輸出可索引類型18的索引空間15映射到對應(yīng)于輸入可索引類型14的索引空間17。通過這樣做,共同映射的通信算子12將索引空間上的函數(shù)13提升到可索引類型14上的函數(shù),以容許與其他通信算子的可組成性。代碼10包括來自高級通用或數(shù)據(jù)并行編程語言的可被編譯成一個或多個可執(zhí)行代碼(例如,圖4中所示的DP可執(zhí)行代碼138)用于由一個或多個DP最優(yōu)計算節(jié)點(例如,圖4所示的DP最優(yōu)計算節(jié)點121)執(zhí)行的指令序列。在一個實施例中,代碼10包括來自具有數(shù)據(jù)并行擴展的高級通用編程語言(之后稱為GP語言)的指令序列,所述指令序列形成存儲在一個或多個模塊的集合中的程序。GP語言可允許程序被編寫在不同部分(即模塊)中,使得每個模塊都可以被存儲在可以由計算機系統(tǒng)訪問的分開的文件或者位置中。GP語言提供用于對包括一個或多個通用處理器和一個或多個專用的DP最優(yōu)計算節(jié)點的計算環(huán)境進行編程的單個語言。DP最優(yōu)計算節(jié)點通常是通用處理器的圖形處理單元(GPU)或SMD單元,但也可包括通用處理器的標量或矢量執(zhí)行單元、場可編程門矩陣(FPGA)或一些計算環(huán)境中的其他合適設(shè)備。使用GP語言,程序員可將通用處理器和DP源代碼均包含在代碼10中以便由通用處理器和DP計算節(jié)點分別執(zhí)行,并協(xié)調(diào)通用處理器和DP源代碼的執(zhí)行。在該實施例中,代碼10可以表示任何合適類型的代碼,諸如應(yīng)用、庫函數(shù)或操作系統(tǒng)服務(wù)。GP語言可以通過擴展諸如C或C++之類的廣泛適用的高級且通用的編程語言以包括數(shù)據(jù)并行特征來形成。其中可出現(xiàn)DP特征的通用語言的其他示例包括Java 、PHP、Visual Basic、Perl、Python 、C#、Ruby、Delphi、Fortran、VB、F#、OCaml、Haskell、Erlang、NESL、Chapel以及JavaScript 。GP語言的實現(xiàn)可包括允許程序的不同部分被包括在不同模塊中的豐富鏈接能力。數(shù)據(jù)并行特征提供了利用DP最優(yōu)計算節(jié)點的專用體系結(jié)構(gòu)來允許數(shù)據(jù)并行操作比使用通用處理器(即,非DP最優(yōu)計算節(jié)點)更快或更有效地執(zhí)行的編程工具。GP語言也可以是允許程序員對通用處 理器和DP最優(yōu)計算節(jié)點兩者均進行編程的另一合適的高級通用編程語言。在另一個實施例中,代碼10包括來自高級數(shù)據(jù)并行編程語言(此后稱DP語言)的形成程序的指令序列。DP語言提供了用于對具有一個或多個DP最優(yōu)計算節(jié)點的計算環(huán)境中的DP最優(yōu)計算節(jié)點進行編程的專用語言。使用DP語言,程序員在代碼10中生成旨在供在DP最優(yōu)計算節(jié)點上執(zhí)行的DP源代碼。DP語言提供了利用DP最優(yōu)計算節(jié)點的專用體系結(jié)構(gòu)來允許數(shù)據(jù)并行操作比使用通用處理器更快或更有效地執(zhí)行的編程工具。DP語言可以是現(xiàn)有的DP編程語言,諸如HLSL、GLSL、Cg、C、C++、NESL, Chapel、CUDA,OpenCL、Accelerator (加速器)、Ct、PGI GPGPU Accelerator (加速器)、CAPS GPGPUAccelerator (加速器)、Brook+、CAL> APL> Fortran 90 (以及更高版本)、Data ParallelC (數(shù)據(jù)并行C)、DAPPLE或APL。在該實施例中,代碼10可以表示任何合適類型的DP源代碼,諸如應(yīng)用、庫函數(shù)或操作系統(tǒng)服務(wù)。
代碼10包括被指定為在DP最優(yōu)計算節(jié)點上執(zhí)行的代碼部分。在使用GP語言來編寫代碼10的圖I的實施例中,GP語言允許程序員在定義矢量函數(shù)時使用注釋26(例如,—dec I spec (vector)...)來指定DP源代碼。注釋26與旨在供在DP最優(yōu)計算節(jié)點上執(zhí)行的矢量函數(shù)的函數(shù)名27(例如vector_func)相關(guān)聯(lián)。代碼10還可包括在調(diào)用點(諸如,foralll (對于全部),reduce (縮減),scan(掃描),或sort (排序))處對矢量函數(shù)的一個或多個調(diào)用28 (例如,scan. . . , vector_func,...)。對應(yīng)于調(diào)用點的矢量函數(shù)被稱為內(nèi)核函數(shù)。內(nèi)核函數(shù)可調(diào)用代碼10中的其他矢量函數(shù)(即,其他DP源代碼),并可被視為矢量函數(shù)調(diào)用圖中的根。內(nèi)核函數(shù)還可使用由代碼10所定義的用戶定義的類型(例如,類或結(jié)構(gòu)體)。這些類型可以被注釋為DP源代碼或可以不被注釋成DP源代碼。在其他實施例中,可使用其他合適的編程語言結(jié)構(gòu)體來將代碼10的各部分指定為DP源代碼和/或通用處理器代碼。此外,在使用DP語言來編寫代碼10的實施例中,注釋26可以被省略。圖2是示出根據(jù)函數(shù)13將共同映射通信算子12應(yīng)用于輸入可索引類型14以產(chǎn)生輸出可索引類型18的實施例的框圖??伤饕愋偷南聵怂阕哟颂幰脖环Q為索引算子。如此處所使用的,可索引類型是實現(xiàn)帶有為非負整數(shù)的秩以及被表示為elementjype的類型的一個或多個下標算子的任何數(shù)據(jù)類型。如果indeX〈N> (索引〈N 是表示整數(shù)的N元組的類型(即,任何類型的整數(shù)數(shù)據(jù)類型),那么indeX〈N>的實例就是N個整數(shù)的集合U0,il,. . . , im},其中m等于N-I (即,N元組)。秩N的索引算子采用index〈N>的N元組實例,并將該實例與被稱為元素類型的類型的另一實例相關(guān)聯(lián),其中元素類型以可索引類型定義了每個元素。在一個實施例中,可索引類型定義以下算子中的一個或多個element_type operator[](index_declarator);const element_type operator[](index_declarator)const ;element_type& operator[] (index_declarator);const element_type& operator[](index_declarator)const ;element_type&& operator [] (index_declarator);或者const element_type&& operator[](index_declarator)const ;其中index_declarator (索引_說明符)采用以下中的至少一個形式const index<rank>& idx ;const index<rank>idx ;index<rank>& idx ;index<rank>idx.在其他實施例中,算子可以是函數(shù)、函子或更通用的表示??伤饕愋偷男螤钍菫槠涠x上述下標算子之一的indeX〈rank> (索引〈秩 >)的集合。可索引類型一般具有多面體的形狀-即,可索引類型可被代數(shù)地表示為由坐標軸的線性函數(shù)所形成的有限數(shù)量個半空間的交點。參看圖I和圖2,在數(shù)據(jù)并行計算環(huán)境中,代碼10的高級語言提供了共同映射通信算子12,其根據(jù)函數(shù)13(如,圖I示例中的函數(shù)f)和輸入可索引類型14(如,圖I示例中的可索引類型indexable_type2)來變換索引空間15(如,圖I示例中的idx)以產(chǎn)生輸出可索引類型18。輸入可索引類型14具有秩(例如,圖I示例中的秩N)和元素類型(例如,圖I示例中的的元素類型T),其中輸入可索引類型14的元素定義了函數(shù)“阿爾法”。共同映射通信算子12將函數(shù)13應(yīng)用到索引空間15來將索引空間15映射至索引空間17。例如,函數(shù)f可表示為從索引空間15的M個索引點i (I)到i(M)的集合(即,index<M>)到索引空間17的N個索引點j (I)到j(luò) (N)的集合(即,index〈N>)的變換,其中M可以等于N或者可以不等于N,如下。f index<M> => index<N> 共同映射通信算子12可被表示為co—map (f) :indexable—type2 => indexable—typel其中co_map(f)的定義是由于可索引類型是由其下標算子的行為唯一地定義的,所以令阿爾法是indexable_type2 的兀素,因此 co_map(f) (alpha)是 indexable_typel 的兀素,因此對于index〈M> 中的每一個 idx,co_map(f) (alpha) (idx)被定義為等于alpha (f (idx))。上述被稱為“f”的預(yù)先合成,注意“f”的方向是顛倒的。共同映射通信算子12通過將函數(shù)13作為自變量而形成更高階的函數(shù)。通過這樣做,共同映射通信算子12將函數(shù)13提升到輸入可索引類型14上的函數(shù)。如圖2中所示,輸入可索引類型14(即,indexable_type2)對應(yīng)于索引空間17(即,index〈N>),如虛線箭頭19所表示,通過可索引類型的定義,這意味著indexable_type2具有如下的索引算子,其中表示左值引用、右值應(yīng)用或者按值返回的語義。element-typeioperator[] (const index〈N>&idx);類似地,輸出可索引類型18 (即,indexable_typel)對應(yīng)于索引空間15 (即,index〈M>),如虛線箭頭20所表示,通過可索引類型的定義,這意味著indexable_typel具有如下的索引算子,其中‘@,表示左值引用、右值引用或者按值返回的語義。element-typeioperator[] (const index〈M>&idx);由于輸出可索引類型18可由其他通信算子操作,所以共同映射通信算子12與其他通信算子是可組成的。為使共同映射通信算子12與其他通信算子完全地可組成,根據(jù)一個實施例可指定四個索引變換(即,transform(變換)、transform_offset (變換_偏移值)、transform_extent (變換 _ 范圍)以及 co_transform_extent (補 _ 變換 _ 范圍))。transform索引變換將索引空間15 (即,index〈_Rankl>)映射到索引空間17 (即,index〈_Rank2>),且可被表示如下,其中_Parent表示輸入可索引類型14、_Index是索引空間15的元素、_Rankl表示輸出可索引類型18的秩、_Rank2表示輸入可索引類型14的秩、以及表示左值引用、右值引用或者按值返回的語義。//index op => return—Parent [transform (_Index)];const index<_Rank2>@transform(const index〈—Rankl>&—Index)const ;transform—offset索引變換將進入可索引類型14的偏移值變換為進入輸出可索引類型18的偏移 值,且可被表示如下。//—Parent, offset = transform—offset(offset);const index<_Rank2>@transform_offset(const index<_Rankl>&_Index)const ;transform— _extent索引變換將可索引空間14的范圍變換成輸出可索引類型18的范圍,且可被表示如下。//_Parent. extent = transform_extent(extent);const extent<_Rank2>itransform_extent(const extent〈_Rankl>& ext)const ;co_transform_extent索引變換將輸出可索引類型18的范圍變換到可索引類型14的范圍,且可被表示如下。//extent = cotransform_extent(_Parent. extent);const extent<_Rankl>icotransform_extent(const extent〈_Rank2>& ext)const ;上述四個索引變換可出現(xiàn)在傳送給共同映射通信算子12的_1^3118;1;'01'1]1_;[11(161對象中。transform_offset>transform_extent> 以及 co_transform_extent 索丐丨變換容i午奪可索引類型分小塊、分節(jié)、或分區(qū)的通信算子與共同映射通信算子12組成起來。使用模板元編程技術(shù),輸出可索引類型18( S卩,共同映射通信算子12的返回類型)的索引算子,當(dāng)被應(yīng)用到按左值引用返回的輸入可索引類型14的時候按左值引用返回、當(dāng)被應(yīng)用到按右值引用返回的輸入可索引類型14的時候按右值引用返回、或者當(dāng)被應(yīng)用到按值返回的輸入可索引類型14的時候按值返回。下面將描述共同映射通信算子12的示例實現(xiàn)。作為如下第一個代碼示例,使用索引變換來實現(xiàn)共同映射通信算子12來形成投射通信算子,_project,它將指定的維插入可索引類型中。例如_project<l> (17) (y, x) = > (y, 17, x)_pro ject<0> (13) (y, x) = > (y, x, 13)另字段〈2,_Element_type>是輸入可索引類型。另f是輸入可索引類型的元素。那么共同映射通信算子12可被表示如下。co_map (_pro ject<l> (17)) (f) (y, x) = > f (_pro ject<l> (17) (y, x))co_map (_pro ject<0> (13)) (f) (y, x) = > f (_pro ject<0> (13) (y, x))這與以下相同co_map (_pro ject<l> (17)) (f) (y, x) = > f (y, 17, x)co_map (_pro ject<0> (13)) (f) (y, x) = > f (y, x, 13)帶有索引變換的投射函子可被如下表示。Il
Il project—functor — —M—bound 是—Parent.get—extent(—Dim)
Il
template <int Dim> struct project—functor {
project—functor(index—t Val, extent—t Bound)
:M value( Val), —M—bound(—Bound)
{
}
template<int Rank, template <int> class —Index—type>
const—Index—type<—Rank+1 >transform_pattern(const
—Index—type<—Rank>& Index) const {
static_assert(—Dim >= 0 && Dim <= Rank && Rank > 0, "illegaldimension for project");
—Index—type<—Rank> —idx; for (int i = 0; i < —Dim; ++i)
—idx[i] = _Index[i];
Index= —M—value; for (int i = —Dim; i < —Rank-1; ++i)
—idx[i+l] = _Index[i]; return idx;}
template<int _Rank>
const index< Rank+1> transform(const index< Rank>& Index) const { return transform—pattern(—Index);
}
template <int —Rank〉
const index<_Rank+1> transform_offset(const index<_Rank>& Index) const
{
return transform—pattern(—Index);
}
template <int _Rank>
const extent<_Rank+1> transform_extent(const extent<_Rank>& Extent)const {
return transform—pattern(—Index);
}
template<int —Rank〉
const extent<_Rank-1> cotransform_extent(const extent<_Rank>& Extent)const {
static_assert(_Dim >= 0 && —Dim < Rank && —Rank > 0,"illegaldimension for project");
extent<_Rank-1> ext;for (int i = 0; i < —Dim; ++i)ext[i] = Extent [i];for (int i = —Dim; i < —Rank-1; ++i)
—ext[i] = _Extent[i+l]; return ext;
}
private:
index—t _M—value;
extent—t —M—bound;
};當(dāng)性能是需要考慮的時候,可如以下示例所示地具體化transform或者
transform_patternο
template <>
const index<l> transform<0>(const index<0>& Index) const {static assert(_Dim == 0, "illegal dimension for project");return index< I >(_M_value);
}
template<>
const index<2> transform< l>(const index<l>& Index) const {
static assert(_Dim == 0 || —Dim == I, "illegal dimension for project"); if ( Dim == 0)
return index<2>(—M—value, Index
);return index<2>(_Index
, —M—value);
}
template<>
const index<3> transform<2>(const index<2>& Index) const {
static_assert(—Dim >= 0 && Dim < 3, "illegal dimension for project");if ( Dim == 0)
return index<3>(—M—value, —lndex
, _Index[l]);else if ( Dim == I)
return index<3>(_Index
, —M—value, _Index[l]);return index<3>(_Index
,」ndex[l], —M—value);
}
template<>
const index<4> transform<3>(const index<3>& Index) const { static_assert(—Dim >= O && Dim < 4, "illegal dimension for project"); if ( Dim == 0)
return index<4>(—M—value, —lndex
,」ndex[l],」ndex[2]);else if ( Dim == I)
return index<4>(_Index
, —M—value, _Index[I],」ndex[2]); else if ( Dim == 2) return index<4>(—lndex
, _Index[I], —M—value, _Index[2]); return index<4>(_Index
,」ndex[l], _Index[2], —M—value);
}第二個代碼示例提供實現(xiàn)共同映射通信算子12來執(zhí)行在一個維度中的輸入可索引類型14的環(huán)形移位(即,c移位(cshift))的索引變換,如下。
template <int —Rank〉
—DECLSPEC—VECTOR
const index<—Rank〉transform(const index<_Rank>& Index) const { index<2> —idx(—Index);
—idx= ( idx+ —M—value) % —M—bound;return idx;
}
template <int —Rank〉
—DECLSPEC—VECTOR
const index<_Rank>& transform—offset(const index<_Rank>& Index)
const {
static_assert(—Dim >= 0 && Dim <= Rank && Rank > 0,"illegal values for cshift");
return Index;
}
template <int _Rank>
—DECLSPEC—VECTOR const extent<_Rank> transform_extent(const extent<_Rank>& ext) const
{
static assert(_Dim >= 0 && Dim <= Rank && Rank > 0,"illegal values for cshift");
return ext;
}
template <int —Rank〉
—DECLSPEC—VECTOR
const extent<—Rank〉cotransform—extent(const extent<_Rank>& ext)
const {
static_assert(—Dim >= 0 && Dim <= Rank && Rank > 0,"illegal values for cshift");
return ext;
}在接下來的第三代碼示例中,如在圖3A-3C中所示,使用索引變換來實現(xiàn)共同映射通信算子12來形成在邊界處將輸入可索引類型14(1)截斷由_Delta指定的量的內(nèi)部通
信算子。
Il
Il內(nèi)部通信算子 Il
template <int Rank, typename —Parent—type〉
interior—range<—Parent—type〉interior(const —Parent—type& Parent, constextent<_Rank>& Delta) {
return interior—range<—Parent—type>(—Parent, Delta);
}使用形成如圖3A中所示的6x6矩陣的輸入可索引類型14 (I),當(dāng)_Delta具有對于每個分量為I的值時,內(nèi)部(—Parent,—Delta)的輸出被圖不為圖3B中的陰影區(qū)域。extent<2>_Delta(l, I);使用內(nèi)部通信算子,transform索引變換是恒等式(identity),因為當(dāng)從索引算子級別看來,沒有任何改變。相應(yīng)地,transform索引變換如下。
const index〈_Rank>& transform(const index〈_Rank>&_Index)const{return_Index ;}transforn^offset索引變換的目的是為了表示從父根(即,原始可索引類型,在這個示例中,是圖3A中所示的6x6矩陣)的角度而言,對于可索引類型14(1)的陰影內(nèi)部中的偏移向量發(fā)生了什么。圖3B的陰影內(nèi)部區(qū)域的子對象可用另一個內(nèi)部通信算子來操作,以產(chǎn)生如圖3C中所示的第二陰影內(nèi)部區(qū)域。圖3C中所示的第二陰影內(nèi)部區(qū)域相對于父根的的偏移量是index〈2>(2,2)。然而,當(dāng)相對于如圖3B中所示的第一陰影內(nèi)部區(qū)域取值時,然而,偏移量是index〈2>(l, I)。相應(yīng)地,transform_offset索引變換如下。const index<_Rank>transform_offset(const index〈_Rank>&_Index)const{return_Index+_M_delta ;//_M_delta = _Delta = (I, I)}transform— .extent索引變換的目的是為了表示從如圖3A中所示的父根的角度而言,對于如圖3B中所示的可索引類型14⑴的第一陰影內(nèi)部的范圍發(fā)生了什么。在這個示例中,通過增加向量2*_Delta(即,6-4 = 2*1且6_4 = 2*1)來在4x4矩陣和6x6矩陣之間變換,如下const extent<_Rank>transform_extent(const extent〈_Rank>&_Extent)const{return_Extent+2*_M_delta ;//_M_delta = _Delta = (I, I)}cotransform_extent (補變換_范圍)索引變換的目的是為了表示從如圖3B中陰影內(nèi)部所示的當(dāng)前子的角度而言,對于如圖3A中所示的父根的范圍(即,6x6矩陣)發(fā)生了什么。在這個示例中,通過增加向量2*_Delta(即,4-6 = -2*1且4_6 = -2*1)來在4x4矩陣和6x6矩陣之間變換,如下。const extent<_Rank>cotransform_extent (const extent〈_Rank>&_Extent)const{return_Extent_2*_M_delta ;//_M_delta = _Delta = (I, I)}在上述中,圖3C中所示的第二陰影內(nèi)部區(qū)域形成如圖3B中所示的第一陰影內(nèi)部區(qū)域的內(nèi)部對象的子對象。為了創(chuàng)建內(nèi)部對象的子對象,將內(nèi)部對象變換回如圖3A中所示的父根(如,_Parent),然后執(zhí)行變換來映射回子對象級別(如,_Parent. _Parent. _Parent)。在一個實施例中,內(nèi)部和其他共同映射通信算子的子對象構(gòu)造函數(shù)(constructor)如下。Il
//限制算子ctor,用于分塊和投射以及一般子對象創(chuàng)建 Il
template <typename _Other_parent type>
transform—range(const grid<_Rank>& Grid, const _Other_parent_type&Parent)
:—Parent—type(_Parent) { s et_offset(_Grid. g et—offset()); s et_extent(_Grid. get_extent());
}
// 其中 set—offset 和 set—extent 看似
void set—offset(const index<_Rank>& Offset) {
Parent type::set_offset( m_transformer.transform_offset(_Offset));
}
void set_extent(const extent<_Rank>& Extent) {
—Parent—type::set—extent( m transformer.transform extent( Extent));
}因此,當(dāng)從圖3A的6x6矩陣變換到圖3B的4x4矩陣、變換到到圖3C的2x2矩陣的時候(即,應(yīng)用內(nèi)部通信算子兩次,每一次使用(1,1)的delta),如下(2x2). set_offset (x, y) = > (4x4). set_offset (x+1, y+1) = > (6x6). set_offset(x+2, y+2)以及(2x2). set_extent (x, y) = > (4x4). set_extent (x+1, y+1) = > (6x6). set_extent(x+2, y+2)相應(yīng)地,可使用下列代碼const extent〈_Rank>get_extentO const{return m_transformer, cotransform_extent(_Parent_type::get_extent ());} 使用上述代碼,child, get—extent (子.獲取—范圍)把子對象的范圍表示為父根的范圍的變換。由此(2x2) · get—extent O = > (4x4) · get—extent O_2*—Delta = > (6x6). get—extent ()-2*—Delta_2*—Delta
可將使用上述索引變換的內(nèi)部函子如下表達。
Il
Il interior—functor(內(nèi)部—函子)
Il
template <int —Rank〉struct interior—functor {
interior—functor(const extent<_Rank>& Delta)
:Mdelta(Delta)
{
}
const index<_Rank>& transform(const index<_Rank>& Index) const { return Index;
}
const index<—Rank〉transform_offset(const index<_Rank>& Index)
const {
return Index + M delta;
}
const extent<_Rank> transform_extent(const extent<_Rank>& Extent)
const {
return Extent + 2*—M delta;
}
const extent<_Rank> cotransform_extent(const extent<_Rank>& Extent)
const {
return Extent - 2*_M_delta;
} private:
extent<_Rank> M delta;
};
在下面的第四代碼示例中,transform索引變換實現(xiàn)對換輸入可索引類型14的維Diml和Dim2的共同映射通信算子12。
template <int —Rank〉
—DECLSPEC—VECTOR
stati c const index<—Rank〉transform(const index<_Rank>& Index) {static—assert(—Diml != Dim2 && —Diml >= 0 && _Dim2 >= 0&& —Diml < —Rank && Dim2 < —Rank && —Rank > 0, "illegal values fortranspose indices");
index<—Rank〉idx;if ( Dim I < _Dim2) {
for (int i = 0; i < —DimI; ++i)
_idx[i] = _Index[i]; for (int i = —Dim 1+1; i < _Dim2; ++i)
_idx[i] = _Index[i]; for (int i = _Dim2+1; i < Rank; ++i)
_idx[i] = _Index[i];
} else {
for (int i = 0; i < _Dim2; ++i)
_idx[i] = _Index[i]; for (int i = _Dim2+1; i < —DimI; ++i)
_idx[i] = _Index[i]; for (int i = —Dim 1+1; i < Rank; ++i)
_idx[i] = _Index[i];
}
—idx[—Diml] = _Index[_Dim2];
_idx[_Dim2] = _Index[_Dim I]; return idx;
}在這個情況下,上述代碼還是 transform—offset、transform—extent、以及 co—transform_extent索引變換的模式。圖4是示出被配置成編譯并執(zhí)行包括共同映射通信算子12的數(shù)據(jù)并行代碼10的計算機系統(tǒng)100的實施例的框圖。
計算機系統(tǒng)100包括具有容納在一個或多個處理器封裝(未示出)中的一個或多個處理元件(PE) 102以及存儲器系統(tǒng)104的主機101。計算機系統(tǒng)100還包括零個或更多個輸入/輸出設(shè)備106、零個或更多個顯示設(shè)備108、零個或更多個外圍設(shè)備110和零個或更多個網(wǎng)絡(luò)設(shè)備112。計算機系統(tǒng)100還包括具有一個或多個DP最優(yōu)計算節(jié)點121的計算引擎120,其中每一 DP最優(yōu)計算節(jié)點121包括一個或多個處理元件(PE) 122的集合和存儲DP可執(zhí)行代碼138的存儲器124。主機101、輸入/輸出設(shè)備106、顯不設(shè)備108、外圍設(shè)備110、網(wǎng)絡(luò)設(shè)備112和計算
引擎120使用包括任何合適的類型、數(shù)量和配置的控制器、總線、接口、和/或其他有線或無線連接的一組互連114來進行通信。計算機系統(tǒng)100表示出于通用或?qū)S媚康亩渲玫娜魏魏线m的處理設(shè)備。計算機系統(tǒng)100的示例包括服務(wù)器、個人計算機、膝上型計算機、圖形輸入板計算機、智能電話、個人數(shù)字助理(PDA)、移動電話、和音頻/視頻設(shè)備。計算機系統(tǒng)100的組件(即,主機101、輸入/輸出設(shè)備106、顯不設(shè)備108、外圍設(shè)備110、網(wǎng)絡(luò)設(shè)備112、互連114和計算引擎120)可包含在公共外殼(未不出)中或任何合適數(shù)量的分立外殼(未不出)中。處理元件102各自形成被配置成執(zhí)行存儲在存儲器系統(tǒng)104中的指令(即軟件)的執(zhí)行硬件。每一處理器封裝中的處理元件102可具有相同或不同的體系結(jié)構(gòu)和/或指令集。例如,處理元件102可以包括順序執(zhí)行元件、超標量執(zhí)行元件、以及數(shù)據(jù)并行執(zhí)行元件(例如GPU執(zhí)行元件)的任何組合。每一處理元件102被配置為訪問并執(zhí)行存儲在存儲器系統(tǒng)104中的指令。這些指令可包括基本輸入輸入系統(tǒng)(BIOS)或固件(未示出)、操作系統(tǒng)(OS) 132、代碼10、編譯器134、GP可執(zhí)行代碼136以及DP可執(zhí)行代碼138。每一處理元件102可以結(jié)合或響應(yīng)于從輸入/輸出設(shè)備106、顯示設(shè)備108、外圍設(shè)備110、網(wǎng)絡(luò)設(shè)備112和/或計算引擎120接收到的信息來執(zhí)行指令。主機101引導(dǎo)并執(zhí)行OS 132。OS 132包括可以由處理元件執(zhí)行以管理計算機系統(tǒng)100的組件并提供允許程序訪問并使用這些組件的一組功能的指令。在一實施例中,OS132是Windows操作系統(tǒng)。在其他實施例中,OS 132是適于和計算機系統(tǒng)100 —起使用的
另一操作系統(tǒng)。當(dāng)計算機系統(tǒng)執(zhí)行編譯器134來編譯代碼10時,編譯器134生成一個或多個可執(zhí)行代碼一例如,一個或多個GP可執(zhí)行代碼136和一個或多個DP可執(zhí)行代碼138。在其他實施例中,編譯器134可生成一個或多個GP可執(zhí)行代碼136以使每個GP可執(zhí)行代碼136包括一個或多個DP可執(zhí)行代碼138,或可生成一個或多個DP可執(zhí)行代碼138而不生成任何GP可執(zhí)行代碼136。GP可執(zhí)行代碼136和/或DP可執(zhí)行代碼138是響應(yīng)于為了編譯代碼10的全部或所選部分對具有數(shù)據(jù)并行擴展的編譯器134的調(diào)用來生成的。該調(diào)用可以由例如程序員或計算機系統(tǒng)100的其他用戶或者計算機系統(tǒng)100中的其他代碼或另一個計算機系統(tǒng)(未示出)的其他代碼來生成。GP可執(zhí)行代碼136表示旨在供在一個或多個通用處理元件102 (例如中央處理單元(CPU))上執(zhí)行的程序。GP可執(zhí)行代碼136包括來自一個或多個通用處理元件102的指令集的低級指令。DP可執(zhí)行代碼138表示旨在并被優(yōu)化成在一個或多個數(shù)據(jù)并行(DP)最優(yōu)計算節(jié)點121上執(zhí)行的數(shù)據(jù)并行程序或算法(例如著色器)。在一個實施例中,DP可執(zhí)行代碼138包括DP字節(jié)代碼或者在DP最優(yōu)計算節(jié)點121上被執(zhí)行之前使用設(shè)備驅(qū)動程序(未示出)被轉(zhuǎn)換成來自DP最優(yōu)計算節(jié)點121的指令集的低級指令的某種其他中間表示(IL)。在其他實施例中,DP可執(zhí)行代碼138包括來自一個或多個DP最優(yōu)計算節(jié)點121的指令集的低級指令,其中該低級指令是由編譯器134插入的。因此,GP可執(zhí)行代碼136可以由一個或多個通用處理器(諸如,CPU)直接執(zhí)行,并且DP可執(zhí)行代碼138或可以由一個或多個DP最優(yōu)計算節(jié)點121直接執(zhí)行或可以在被轉(zhuǎn)換成DP最優(yōu)計算節(jié)點121的低級指令以后由一個或多個DP最優(yōu)計算節(jié)點121來執(zhí)行。計算機系統(tǒng)100可使用一個或多個處理元件102來執(zhí)行GP可執(zhí)行代碼136,并且計算機系統(tǒng)100可使用下文中更詳細描述的一個或多個PE 122來執(zhí)行DP可執(zhí)行代碼138。存儲器系統(tǒng)104包括被配置成存儲指令和數(shù)據(jù)的任何合適的類型、數(shù)量和配置的易失性或非易失性存儲設(shè)備。存儲器系統(tǒng)104的儲存設(shè)備表示儲存包括OS 132、代碼10、編譯器134、GP可執(zhí)行代碼136以及DP可執(zhí)行代碼138的計算機可執(zhí)行指令(即軟件)的計算機可讀儲存介質(zhì)。指令可由計算機系統(tǒng)100執(zhí)行以實現(xiàn)此處所述的OS 132、代碼10、編譯器134、GP可執(zhí)行代碼136以及DP可執(zhí)行代碼138的功能和方法。存儲器系統(tǒng)104存儲從處理元件102、輸入/輸出設(shè)備106、顯示設(shè)備108、外圍設(shè)備110、網(wǎng)絡(luò)設(shè)備112和計算引擎120接收的指令和數(shù)據(jù)。存儲器系統(tǒng)104將所存儲的指令和數(shù)據(jù)提供給處理元件102、輸入/輸出設(shè)備106、顯不設(shè)備108、外圍設(shè)備110、網(wǎng)絡(luò)設(shè)備112和計算引擎120。存儲器系統(tǒng)104中的存儲設(shè)備的示例包括硬盤驅(qū)動器、隨機存取存儲器(RAM)、只讀存儲器(ROM)、閃存驅(qū)動器和卡、以及諸如⑶和DVD之類的磁盤和光盤。輸入/輸出設(shè)備106包括被配置成將指令或數(shù)據(jù)從用戶輸入到計算機系統(tǒng)100并將指令或數(shù)據(jù)從計算機系統(tǒng)100輸出到用戶的任何合適的類型、數(shù)量和配置的輸入/輸出設(shè)備。輸入/輸出設(shè)備106的示例包括鍵盤、鼠標、觸摸墊、觸摸屏、按鈕、撥盤、旋鈕和開關(guān)。顯示設(shè)備108包括被配置成向計算機系統(tǒng)100的用戶輸出文本和/或圖形信息的任何合適的類型、數(shù)量和配置的顯示設(shè)備。顯示設(shè)備108的示例包括監(jiān)視器、顯示屏和投影儀。外圍設(shè)備110包括被配置成用計算機系統(tǒng)100中的一個或多個其他組件來操作以執(zhí)行通用或?qū)S锰幚砉δ艿娜魏魏线m的類型、數(shù)量和配置的外圍設(shè)備。網(wǎng)絡(luò)設(shè)備112包括被配置成允許計算機系統(tǒng)100跨一個或多個網(wǎng)絡(luò)(未示出)進行通信的任何合適的類型、數(shù)量和配置的網(wǎng)絡(luò)設(shè)備。網(wǎng)絡(luò)設(shè)備112可根據(jù)任何合適的網(wǎng)絡(luò)協(xié)議和/或配置來操作以允許計算機系統(tǒng)100將信息發(fā)送給網(wǎng)絡(luò)或者從網(wǎng)絡(luò)接收信息。計算引擎120被配置成執(zhí)行DP可執(zhí)行代碼138。計算引擎120包括一個或多個計算節(jié)點121。每一計算節(jié)點121是共享一存儲器分層結(jié)構(gòu)的計算資源的集合。每一計算節(jié)點121包括一個或多個PE 122的集合以及存儲DP可執(zhí)行代碼138的存儲器124。PE 122 執(zhí)行DP可執(zhí)行代碼138并將由DP可執(zhí)行代碼138生成的結(jié)果儲存在存儲器124中。具體地,PE 122執(zhí)行DP可執(zhí)行代碼138以將共同映射通信算子12應(yīng)用于輸入可索引類型14以生成如圖4所示的且如上文中詳細描述的輸出可索引類型18。
具有一個或多個計算資源且該資源具有為數(shù)據(jù)并行計算(即,執(zhí)行DP程序或算法)而優(yōu)化的硬件體系結(jié)構(gòu)的計算節(jié)點121被稱為DP最優(yōu)計算節(jié)點121。DP最優(yōu)計算節(jié)點121的示例包括其中PE 122的集合包括一個或多個GPU的節(jié)點121,以及其中PE 122的集合包括通用處理器封裝中的SMD單元的集合的節(jié)點121。不具有帶有為數(shù)據(jù)并行計算而優(yōu)化的硬件體系結(jié)構(gòu)的任何計算資源的計算節(jié)點121 (例如,僅僅具有通用處理元件102的處理器封裝)被稱為非DP最優(yōu)計算節(jié)點121。在每一計算節(jié)點121中,存儲器124可與存儲器系統(tǒng)104分開(諸如,GPU所使用的GPU存儲器),或可以是存儲器系統(tǒng)104的一部分(例如,通用處理器封裝102中的SMD單元所使用的存儲器)。主機101形成被配置成將DP可執(zhí)行代碼138提供給計算節(jié)點121以供執(zhí)行并且使用互連114接收由DP可執(zhí)行代碼138生成的結(jié)果的主機計算節(jié)點。主機計算節(jié)點包括共享一存儲器分層結(jié)構(gòu)(即,存儲器系統(tǒng)104)的通用計算資源(即,通用處理元件102)的集合。主機計算節(jié)點可被配置成具有對稱多處理體系結(jié)構(gòu)(SMP),并且還可被配置為使用例 如非均勻存儲器存取(NUMA)體系結(jié)構(gòu)來最大化存儲器系統(tǒng)104的存儲器局部性。主機計算節(jié)點的OS 132被配置為執(zhí)行DP調(diào)用點以使DP可執(zhí)行代碼138被DP最優(yōu)計算節(jié)點或非DP最優(yōu)計算節(jié)點121執(zhí)行。在其中存儲器124與存儲器系統(tǒng)104分開的實施例中,主機計算節(jié)點使DP可執(zhí)行代碼138以及一個或多個可索引類型14從存儲器系統(tǒng)104復(fù)制到存儲器124。在其中存儲器系統(tǒng)104包括存儲器124的實施例中,主機計算節(jié)點可將存儲器系統(tǒng)104中的DP可執(zhí)行代碼138和/或一個或多個可索引類型14的副本指定為存儲器124,和/或?qū)P可執(zhí)行代碼138和/或一個或多個可索引類型14從存儲器系統(tǒng)104的一部分復(fù)制到形成存儲器124的存儲器系統(tǒng)104的另一部分中。在計算節(jié)點121和主機計算節(jié)點之間的復(fù)制過程可以是同步點,除非它被指定為是異步的。主機計算節(jié)點和每一計算節(jié)點121可并發(fā)地彼此獨立地執(zhí)行代碼。主機計算節(jié)點和每一計算節(jié)點121可在同步點處進行交互以協(xié)調(diào)節(jié)點計算。在一個實施例中,計算引擎120表示圖形卡,其中一個或多個圖形處理單元(GPU)包括PE 122以及與存儲器系統(tǒng)104分開的存儲器124。在該實施例中,圖形卡的驅(qū)動程序(未示出)可以將DP可執(zhí)行代碼138的字節(jié)代碼或某種其他中間表示(IL)轉(zhuǎn)換成GPU的指令集以供GPU的PE 122執(zhí)行。在另一實施例中,從一個或多個GPU ( S卩,PE 122)的組合中形成計算引擎120,該一個或多個GPU被包括在具有一個或多個通用處理元件102以及包括存儲器124的存儲器系統(tǒng)104的一部分的處理器封裝中。在該實施例中,可以在計算機系統(tǒng)100上提供附加軟件來將DP可執(zhí)行代碼138的字節(jié)代碼或某種其他中間表示(IL)轉(zhuǎn)換成處理器封裝中的GPU的指令集。在另一實施例中,從一個或多個處理器封裝中的一個或多個SMD單元的組合中形成計算引擎120,該一個或多個處理器封裝包括處理元件102以及包括存儲器124的存儲器系統(tǒng)104的一部分。在該實施例中,可以在計算機系統(tǒng)100上提供附加軟件來將DP可執(zhí)行代碼138的字節(jié)代碼或某種其他中間表示(IL)轉(zhuǎn)換成處理器封裝中的SMD單元的指令集。在又一實施例中,從一個或多個處理器封裝中的一個或多個標量或矢量處理流水線的組合中形成計算引擎120,該一個或多個處理器封裝包括處理元件102以及包括存儲器124的存儲器系 統(tǒng)104的一部分。在該實施例中,可以在計算機系統(tǒng)100上提供附加軟件來將DP可執(zhí)行代碼138的字節(jié)代碼或某種其他中間表示(IL)轉(zhuǎn)換成處理器封裝中的標量處理流水線的指令集。盡管此處說明并描述了具體實施例,但本領(lǐng)域技術(shù)人員可以理解,可用各種替換和/或等價實現(xiàn)來替換所示出并描述的具體實施例而不背離本發(fā)明的范圍。本申請旨在覆蓋此處討論的具體實施例的任何改編或變型。因此,本發(fā)明旨在僅由權(quán)利要求書及其等效方案來限制。
權(quán)利要求
1.一種存儲計算機可執(zhí)行指令的計算機可讀存儲介質(zhì),所述計算機可執(zhí)行指令在由計算機系統(tǒng)執(zhí)行時使得所述計算機系統(tǒng)執(zhí)行一種方法,所述方法包括 響應(yīng)于被配置為在一個或多個數(shù)據(jù)并行計算節(jié)點上執(zhí)行的數(shù)據(jù)并行源代碼中的第一共同映射通信算子,而根據(jù)第一索引空間上的函數(shù),將輸入可索引類型映射到輸出可索引類型;以及 使用所述輸出可索引類型來執(zhí)行數(shù)據(jù)并行算法。
2.如權(quán)利要求I所述的計算機可讀介質(zhì),其特征在于,所述輸入可索引類型具有第一秩和第一元素類型,且所述輸出可索引類型具有第二秩和第二元素類型。
3.如權(quán)利要求I所述的計算機可讀介質(zhì),其特征在于,所述函數(shù)將所述第一索引空間映射到第二索引空間。
4.如權(quán)利要求3所述的計算機可讀介質(zhì),其特征在于,所述第一索引空間對應(yīng)于所述輸出可索引類型,而所述第二索引空間對應(yīng)于所述輸入可索引類型。
5.如權(quán)利要求I所述的計算機可讀存儲介質(zhì),其特征在于,還包括 對所述輸出可索引類型應(yīng)用第二通信算子。
6.如權(quán)利要求I所述的計算機可讀存儲介質(zhì),其特征在于,所述數(shù)據(jù)并行源代碼是用具有數(shù)據(jù)并行擴展的編程語言編寫的。
7.如權(quán)利要求I所述的方法,其特征在于,所述數(shù)據(jù)并行源代碼是用高級數(shù)據(jù)并行編程語言編寫的。
8.如權(quán)利要求I所述的計算機可讀存儲介質(zhì),其特征在于,所述一個或多個數(shù)據(jù)并行計算節(jié)點包括至少一個圖形處理單元。
9.如權(quán)利要求I所述的計算機可讀存儲介質(zhì),其特征在于,所述一個或多個數(shù)據(jù)并行計算節(jié)點包括至少一個通用處理器。
10.一種由計算機系統(tǒng)中的編譯器執(zhí)行的方法,所述方法包括 在被配置成供在一個或多個數(shù)據(jù)并行計算節(jié)點上執(zhí)行的數(shù)據(jù)并行源代碼中標識第一共同映射通信算子;以及 從所述數(shù)據(jù)并行源代碼中產(chǎn)生數(shù)據(jù)并行可執(zhí)行代碼,以使所述數(shù)據(jù)并行可執(zhí)行代碼通過根據(jù)在第一索引空間上的函數(shù)從輸入可索引類型產(chǎn)生輸出可索引類型來實現(xiàn)所述第一共同映射通信算子。
11.如權(quán)利要求10所述的方法,其特征在于,所述輸入可索引類型具有第一秩和第一元素類型,且所述輸出可索引類型具有第二秩和第二元素類型。
12.如權(quán)利要求10所述的方法,其特征在于,所述函數(shù)將所述第一索引空間映射到第二索引空間。
13.如權(quán)利要求12所述的方法,其特征在于,所述第一索引空間對應(yīng)于所述輸出可索引類型,而所述第二索引空間對應(yīng)于所述輸入可索引類型。
14.如權(quán)利要求10所述的方法,其特征在于,還包括 從所述數(shù)據(jù)并行源代碼中產(chǎn)生數(shù)據(jù)并行可執(zhí)行代碼,以使所述數(shù)據(jù)并行可執(zhí)行代碼將第二通信算子應(yīng)用到所述輸出可索引類型。
15.如權(quán)利要求10所述的方法,其特征在于,所述數(shù)據(jù)并行源代碼是用帶有數(shù)據(jù)并行擴展的高級通用編程語言編寫的。
16.如權(quán)利要求10所述的方法,其特征在于,所述數(shù)據(jù)并行源代碼是用高級數(shù)據(jù)并行編程語目編寫的。
17.如權(quán)利要求10所述的方法,其特征在于,所述一個或多個數(shù)據(jù)并行計算節(jié)點包括至少一個圖形處理單元。
18.如權(quán)利要求10所述的方法,其特征在于,所述一個或多個數(shù)據(jù)并行計算節(jié)點包括至少一個通用處理器。
19.一種存儲計算機可執(zhí)行指令的計算機可讀存儲介質(zhì),所述計算機可執(zhí)行指令在由計算機系統(tǒng)執(zhí)行時執(zhí)行一種方法,所述方法包括 根據(jù)第一索引空間上的函數(shù),將共同映射通信算子應(yīng)用于具有第一秩和第一元素類型的輸入可索引類型,來產(chǎn)生具有第二秩和第二元素類型的輸出可索引類型,其中所述輸出可索引類型對應(yīng)于所述第一索引空間;以及 使用所述輸出可索引類型來執(zhí)行數(shù)據(jù)并行算法; 其中所述共同映射通信算子被包括在用帶有數(shù)據(jù)并行擴展的高級通用編程語言編寫的數(shù)據(jù)并行源代碼中。
20.如權(quán)利要求19所述的計算機可讀存儲介質(zhì),其特征在于,所述數(shù)據(jù)并行源代碼被設(shè)置為在包括至少一個圖形處理單元的一個或多個數(shù)據(jù)并行計算節(jié)點上執(zhí)行。
全文摘要
本申請涉及共同映射通信算子。高級編程語言提供了根據(jù)函數(shù)將輸入可索引類型映射到輸出可索引類型的共同映射通信算子。該函數(shù)將對應(yīng)于輸出可索引類型的索引空間映射到對應(yīng)于輸入可索引類型的索引空間。通過這樣做,共同映射的通信算子將索引空間上的函數(shù)提升到可索引類型上的函數(shù)以容許與其他通信算子的可組成性。
文檔編號G06F9/302GK102637123SQ20111043984
公開日2012年8月15日 申請日期2011年12月23日 優(yōu)先權(quán)日2010年12月23日
發(fā)明者D·J·麥克拉迪, P·F·林塞斯, Y·萊瓦諾尼, 張玲莉, 朱偉榮 申請人:微軟公司