array_view without Data Source

In Visual Studio 2012, C++ AMP introduced concurrency::array_view as a primary interface to read and write multi-dimensional data across the CPU and GPU accelerators.

The construction of array_view always required a data source like std::vector, concurrency::array etc. It could be either a CPU pointer or any data container that supports .data() and .size() methods . Even in the scenarios, where a temporary container is required purely as an output buffer and its initial content and backing memory allocation is irrelevant, it is mandated to provide a data source.

Look the below code snippets which illustrate the above point.

 

Example 1:

  1: array_view<const int, 1> arrViewA(M, vecA); // vecA is a const data source of type 'std::vector'
  2: array_view<const int, 1> arrViewB(M, vecB); // vecB is a const data source of type 'std::vector
  3:  
  4: std::vector<int> sumResult(arrViewA.extent.size());
  5: array_view<int, 1> arrViewSum(M,sumResult); // Creation of array_view with resource
  6: arrViewSum.discard_data();
  7:  
  8: parallel_for_each(arrViewSum.extent, [=](const index<1> &amp;idx) restrict(amp) {
  9:      arrViewSum[idx] = arrViewA[idx] + arrViewB[idx];
  10: });
  11: arrViewSum.synchronize();
  12:  
  13: for (size_t i = 0; i < sumResult.size(); ++i) {
  14:      sumResult[i]; // Accessing the result of computation
  15: }

 

 

Example 2:

 

  1: array_view<const int, 1> arrViewA(M, vecA); // vecA is a const data source of type 'std::vector'
  2: array_view<const int, 1> arrViewB(M, vecB); // vecB is a const data source of type 'std::vector'
  3:  
  4: array<int, 1> arrSumResult(arrViewA.extent); // Creating Array object as output buffer
  5: array_view<int, 1> arrViewSum(arrSumResult); // Creation of array_view over array
  6: arrViewSum.discard_data();
  7:  
  8: parallel_for_each(arrViewSum.extent, [=](const index<1> &amp;idx) restrict(amp) {
  9:       arrViewSum[idx] = arrViewA[idx] + arrViewB[idx];
  10: });
  11:  
  12: for (size_t i = 0; i < sumResult.size(); ++i) {
  13:       arrViewSum.data[i]; // Accessing the result of computation
  14: }

 

 

From the above code snippets, we will observe the following shortcomings:

a) Always a data source is required during to array_view construction

b) Requires the developers to learn about concurrency::array, array_view::discard_data.

c) Requires allocating the array on the right accelerator_view where, the array_view will be subsequently accessed. It also requires the users to specify the right accelerator_view to p_f_e, for using the array_view. Failure to specify the right accelerator_view may result in redundant data transfers to the targeted accelerator_view.

In Visual Studio 2013, these shortcomings have been addressed with the provision of “array_view construction without specifying a data source”. In short, this can be considered as creating an array_view, without any data source association and let the runtime allocate the underlying storage lazily as and when the array_view is accessed on accelerator_view or on the CPU.

- array_view without data source can be used only for read-write access. It cannot be constructed for read only purpose i.e., array_view<const T>.

- array_view without data source is just like any other ‘array_view’ object with no data association.

- array_view is initially uninitialized and behaves as if its contents have been “discard” immediately after construction.

- The “synchronize” API (the overload without any accelerator_view explicitly specified) will be a no-op for such an array_view.

Now, let’s rewrite the code snippets given in ‘Example 1’ and ‘Example 2’ using ‘array_view without data source’.

  1: array_view<const int, 1> arrViewA(M, vecA); // vecA is a const data source of type 'std::vector'
  2: array_view<const int, 1> arrViewB(M, vecB); // vecB is a const data source of type 'std::vector'
  3:  
  4: array_view<int, 1> arrViewSum(M); // Creation of array_view without data resource
  5:  
  6: parallel_for_each(arrViewSum.extent, [=](const index<1> &amp;idx) restrict(amp) {
  7:     arrViewSum[idx] = arrViewA[idx] + arrViewB[idx];
  8: });
  9:  
  10: for (size_t i = 0; i < arrViewSum.extent.size(); ++i) {
  11:     arrViewSum.data[i]; // Accessing the result of computation
  12: }

It is vividly evident that ‘array_view without data source’ is simple to use and in deed resulted in fewer lines of code :-)

 

In Closing

In this post we looked at the one of the improvements we’ve made to Array_views in Visual Studio 2013. Stay tuned for more blog posts on the improvements of C++ AMP in Visual Studio 2013. As usual, I would love to read your comments below or in our MSDN forum.