Don't even try that. This double indirection is not used in scientific programming because it makes it harder for the prefetcher to predict what you want. Thus it leads to higher latency and worse code execution speed. This is why the entries of MTensors
are stored in a linear buffer. If out
has bufferSize
columns, then simply access the entry {i,j}
with out[bufferSize * i + j]
.
You might argue that out[bufferSize * i + j]
involves integer arithmetic. But modern processors typically ship with sufficiently many integer units to saturate the memory throughput. Moreover, the integer units are separate from the floating point units. So they do not compete with the latter; they can do their thing concurrently. Anyways, if you want to reduce the intensity of integer arithmetic, you can try things like this:
const mint n = numOfData * bufferSize;
for( mint row_begin = 0; row_begin < n; row_begin += bufferSize )
{
for( mint i = 0; i < bufferSize; ++i )
{
out[row_begin + i] = row_begin + i + 1;
}
}
This involves only additions. Not sure whether this improves anything. IMHO it obfuscates what one really wants to do. And telling from my experience, this is hardly any faster.
I am not quite sure, but it may be that an integer addition costs exactly as much as an integer multiply-add. This depends on the hardware (and on whether the compiler is able to fuse the two operations into one). I have seen this idiom rarely for CPU code, but quite frequently for GPUs (whose cores are not that beefy as a CPU's).
Moreover, compiler developers are aware of these programming habits and thus they put some effort into optimizations like auto-vectorization. For most efficient vectorization, the data has to lie consecutively in memory (otherwise the copy-costs slow it down too much). Then short vectors of this data can be taken and processed as one. Problems arise at the beginning of a matrix row (due to alignment issues) and at the end of the row. The ends have to be peeled, i.e. processed in the "classical" way; this costs extra logic. So from this point of view, the loop might better be reformulated as follows:
const mint n = numOfData * bufferSize;
for( mint i = 0; i < n; ++i )
{
out[i] = i + 1;
}
But maybe the compiler is clever enough to do it on its own (if bufferSize
is a compile-time constant).
Anyways, the real bottleneck is always memory bandwidth and latency.
Edit:
If you have to deal with high-rank tensors, then you might want to use
libData->MTensor_getReal
libData->MTensor_setReal
to extract/modify a single entry. See here for details. I've got the hunch that this will be very slow because indices have to be stored in an array first and this array is read and processed for each query. Plus these routines might also involve bound checks which you might want to skip if you know what you are doing.