File: manual-design.html

package info (click to toggle)
viennacl 1.7.1%2Bdfsg1-6
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, sid, trixie
  • size: 114,428 kB
  • sloc: sh: 454,206; cpp: 109,088; ansic: 2,103; perl: 104; makefile: 22
file content (185 lines) | stat: -rw-r--r-- 14,700 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.6"/>
<title>ViennaCL - The Vienna Computing Library: Design Decisions</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
  $(document).ready(initResizable);
  $(window).load(resizeHeight);
</script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript">
  $(document).ready(function() { searchBox.OnSelectItem(0); });
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td style="padding-left: 0.5em;">
   <div id="projectname">ViennaCL - The Vienna Computing Library
   &#160;<span id="projectnumber">1.7.1</span>
   </div>
   <div id="projectbrief">Free open-source GPU-accelerated linear algebra and solver library.</div>
  </td>
   <td>        <div id="MSearchBox" class="MSearchBoxInactive">
        <span class="left">
          <img id="MSearchSelect" src="search/mag_sel.png"
               onmouseover="return searchBox.OnSearchSelectShow()"
               onmouseout="return searchBox.OnSearchSelectHide()"
               alt=""/>
          <input type="text" id="MSearchField" value="Search" accesskey="S"
               onfocus="searchBox.OnSearchFieldFocus(true)" 
               onblur="searchBox.OnSearchFieldFocus(false)" 
               onkeyup="searchBox.OnSearchFieldChange(event)"/>
          </span><span class="right">
            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
          </span>
        </div>
</td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.6 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'Search');
</script>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('manual-design.html','');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Classes</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Namespaces</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(3)"><span class="SelectionMark">&#160;</span>Files</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(4)"><span class="SelectionMark">&#160;</span>Functions</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(5)"><span class="SelectionMark">&#160;</span>Variables</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(6)"><span class="SelectionMark">&#160;</span>Typedefs</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(7)"><span class="SelectionMark">&#160;</span>Enumerations</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(8)"><span class="SelectionMark">&#160;</span>Enumerator</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(9)"><span class="SelectionMark">&#160;</span>Friends</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(10)"><span class="SelectionMark">&#160;</span>Macros</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(11)"><span class="SelectionMark">&#160;</span>Pages</a></div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="header">
  <div class="headertitle">
<div class="title">Design Decisions </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>During the implementation of ViennaCL, several design decisions were necessary, which are often a trade-off among various advantages and disadvantages. In the following, we discuss several design decisions and the reasoning that has led to the same.</p>
<h1><a class="anchor" id="manual-design-transfer-scalars"></a>
Transfer CPU-GPU-CPU for Scalars</h1>
<p>The ViennaCL scalar type <code>scalar&lt;&gt;</code> essentially behaves like a CPU scalar in order to make any access to GPU ressources as simple as possible, for example </p>
<pre class="fragment">float cpu_float = 1.0f;
viennacl::linalg::scalar&lt;float&gt; gpu_float = cpu_float;

gpu_float = gpu_float * gpu_float;
gpu_float -= cpu_float;
cpu_float = gpu_float;
</pre><p>As an alternative, the user could have been required to use <code>copy</code> as for the vector and matrix classes, but this would unnecessarily complicated many commonly used operations like </p>
<pre class="fragment">if (norm_2(gpu_vector) &lt; 1e-10) { ... }
</pre><p>or </p>
<pre class="fragment">gpu_vector[0] = 2.0f;
</pre><p>where one of the operands resides on the CPU and the other on the GPU. Initialization of a separate type followed by a call to <code>copy</code> iscertainly not desired for the above examples.</p>
<p>However, one should use <code>scalar&lt;&gt;</code> with care, because the overhead for transfers from CPU to GPU and vice versa is very large for the simple <code>scalar&lt;&gt;</code> type.</p>
<dl class="section warning"><dt>Warning</dt><dd>Use <code>scalar&lt;&gt;</code> with care, operations may be much slower than built-in types on the CPU!</dd></dl>
<h1><a class="anchor" id="manual-design-transfer-vectors"></a>
Transfer CPU-GPU-CPU for Vectors</h1>
<p>The present way of data transfer for vectors and matrices from CPU to GPU to CPU is to use the provided <code>copy</code> function, which is similar to its counterpart in the Standard Template Library (STL): </p>
<div class="fragment"><div class="line">std::vector&lt;float&gt; cpu_vector(10);</div>
<div class="line">ViennaCL::LinAlg::vector&lt;float&gt; gpu_vector(10);</div>
<div class="line"></div>
<div class="line"><span class="comment">// fill cpu_vector here</span></div>
<div class="line"></div>
<div class="line"><span class="comment">//transfer values to gpu:</span></div>
<div class="line"><a class="code" href="namespaceviennacl.html#a10b7f8cf6b8864a7aa196d670481a453">copy</a>(cpu_vector.begin(), cpu_vector.end(), gpu_vector.begin());</div>
<div class="line"></div>
<div class="line"><span class="comment">// compute something on GPU here</span></div>
<div class="line"></div>
<div class="line"><span class="comment">//transfer back to cpu:</span></div>
<div class="line"><a class="code" href="namespaceviennacl.html#a10b7f8cf6b8864a7aa196d670481a453">copy</a>(gpu_vector.begin(), gpu_vector.end(), cpu_vector.begin());</div>
</div><!-- fragment --><p> A first alternative approach would have been to to overload the assignment operator like this: </p>
<div class="fragment"><div class="line"><span class="comment">//transfer values to gpu:</span></div>
<div class="line">gpu_vector = cpu_vector;</div>
<div class="line"></div>
<div class="line"><span class="comment">// compute something on GPU here</span></div>
<div class="line"></div>
<div class="line"><span class="comment">//transfer back to cpu:</span></div>
<div class="line">cpu_vector = gpu_vector;</div>
</div><!-- fragment --><p> The first overload can be directly applied to the <code>vector</code>-class provided by ViennaCL. However, the question of accessing data in the <code>cpu_vector</code> object arises. For <code>std::vector</code> and C arrays, the bracket operator can be used, but the parenthesis operator cannot. However, other vector types may not provide a bracket operator. Using STL iterators is thus the more reliable variant.</p>
<p>The transfer from GPU to CPU would require to overload the assignment operator for the CPU class, which cannot be done by ViennaCL. Thus, the only possibility within ViennaCL is to provide conversion operators. Since many different libraries could be used in principle, the only possibility is to provide conversion of the form </p>
<div class="fragment"><div class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</div>
<div class="line"><span class="keyword">operator</span> T() {</div>
<div class="line">  <span class="comment">// implementation here</span></div>
<div class="line">}</div>
</div><!-- fragment --><p> for the types in ViennaCL. However, this would allow even totally meaningless conversions, e.g. from a GPU vector to a CPU boolean and may result in obscure unexpected behavior.</p>
<p>Moreover, with the use of <code>copy</code> functions it is much clearer, at which point in the source code large amounts of data are transferred between CPU and GPU.</p>
<h1><a class="anchor" id="manual-design-solver"></a>
Solver Interface</h1>
<p>We decided to provide an interface compatible to Boost.uBLAS for dense matrix operations. The only possible generalization for iterative solvers was to use the tagging facility for the specification of the desired iterative solver.</p>
<h1><a class="anchor" id="manual-design-iterators"></a>
Iterators</h1>
<p>Since we use the iterator-driven <code>copy</code> function for transfer from CPU to GPU to CPU, iterators have to be provided anyway. However, it has to be repeated that they are usually VERY slow, because each data access (i.e. dereferentiation) implies a new transfer between CPU and GPU. Nevertheless, CPU-cached vector and matrix classes could be introduced in future releases of ViennaCL.</p>
<p>A remedy for quick iteration over the entries of e.g. a vector is the following: </p>
<div class="fragment"><div class="line">std::vector&lt;double&gt; temp(gpu_vector.size());</div>
<div class="line"><a class="code" href="namespaceviennacl.html#a10b7f8cf6b8864a7aa196d670481a453">copy</a>(gpu_vector.begin(), gpu_vector.end(), temp.begin());</div>
<div class="line"><span class="keywordflow">for</span> (std::vector&lt;double&gt;::iterator it = temp.begin();</div>
<div class="line">     it != temp.end();</div>
<div class="line">    ++it)</div>
<div class="line">{</div>
<div class="line">  <span class="comment">//do something with the data here</span></div>
<div class="line">}</div>
<div class="line"><a class="code" href="namespaceviennacl.html#a10b7f8cf6b8864a7aa196d670481a453">copy</a>(temp.begin(), temp.end(), gpu_vector.begin());</div>
</div><!-- fragment --><p> The three extra code lines can be wrapped into a separate iterator class by the library user, who also has to ensure data consistency during the loop.</p>
<h1><a class="anchor" id="manual-design-init"></a>
Initialization of Compute Kernels</h1>
<p>Since OpenCL relies on passing the OpenCL source code to a built-in just-in-time compiler at run time, the necessary kernels have to be generated every time an application using ViennaCL is started.</p>
<p>One possibility was to require a mandatory </p>
<pre class="fragment">viennacl::init();
</pre><p>before using any other objects provided by ViennaCL, but this approach was discarded for the following two reasons:</p>
<ul>
<li>If <code>viennacl::init();</code> is accidentally forgotten by the user, the program will most likely terminate in a rather uncontrolled way.</li>
<li>It requires the user to remember and write one extra line of code, even if the default settings are fine.</li>
</ul>
<p>Initialization is instead done in a lazy manner when requesting OpenCL kernels. Kernels with similar functionality are grouped together in a common compilation units. This allows a fine-grained control over which source code to compile where and when. For example, there is no reason to compile the sparse matrix compute kernels at program startup if there are no sparse matrices used at all.</p>
<p>Moreover, the just-in-time compilation of all available compute kernels in ViennaCL takes several seconds. Therefore, a request-based compilation is used to minimize any overhead due to just-in-time compilation.</p>
<p>The request-based compilation is a two-step process: At the first instantiation of an object of a particular type from ViennaCL, the full source code for all objects of the same type is compiled into an OpenCL program for that type. Each program contains plenty of compute kernels, which are not yet initialized. Only if an argument for a compute kernel is set, the kernel actually cares about its own initialization. Any subsequent calls of that kernel reuse the already compiled and initialized compute kernel.</p>
<dl class="section note"><dt>Note</dt><dd>When benchmarking ViennaCL, a dummy call to the functionality of interest should be issued prior to taking timings. Otherwise, benchmark results include the just-in-time compilation, which is a constant independent of the data size. </dd></dl>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
  <ul>
    <li class="footer">Generated on Wed Jan 20 2016 22:32:44 for ViennaCL - The Vienna Computing Library by
    <a href="http://www.doxygen.org/index.html">
    <img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.6 </li>
  </ul>
</div>
</body>
</html>