   // Compute the output location for each row in-place based on it's 
   // partition number such that each partition will be contiguous in memory
   size_type * row_output_locations{row_partition_numbers};
-  thrust::transform(row_partition_numbers,
+  thrust::transform(thrust::cuda::par,
+                    row_partition_numbers,
                     row_partition_numbers + num_rows,
                     row_output_locations,
                     compute_row_output_location<size_type>(partition_sizes));

  constexpr int rows_per_block = HASH_KERNEL_BLOCK_SIZE * HASH_KERNEL_ROWS_PER_THREAD;
  const int grid_size = (num_rows + rows_per_block - 1) / rows_per_block;

  // Computes which partition each row belongs to by hashing the row and performing
  // a partitioning operator on the hash value. Also computes the number of
  // rows in each partition

          typename size_type>
__global__ 
void compute_row_partition_numbers(gdf_table<size_type> const & the_table, 
                                   const size_type num_rows,
                                   const size_type num_partitions,
                                   const partitioner_type the_partitioner,
                                   size_type * row_partition_numbers,
                                   size_type * partition_sizes)
{
  size_type row_number = threadIdx.x + blockIdx.x * blockDim.x;

