Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
perfMatrixTranspose.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Benchmark matrix transpose.
32  */
33 
38 #include <visp3/core/vpConfig.h>
39 
40 #ifdef VISP_HAVE_CATCH2
41 #define CATCH_CONFIG_ENABLE_BENCHMARKING
42 #define CATCH_CONFIG_RUNNER
43 #include <catch.hpp>
44 
45 #include <visp3/core/vpMatrix.h>
46 
47 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
48 #include <opencv2/core.hpp>
49 #endif
50 
51 #ifdef VISP_HAVE_EIGEN3
52 #include <Eigen/Dense>
53 #endif
54 
55 #ifdef ENABLE_VISP_NAMESPACE
56 using namespace VISP_NAMESPACE_NAME;
57 #endif
58 
59 namespace
60 {
61 
62 bool g_runBenchmark = false;
63 int g_tileSize = 16;
64 
65 vpMatrix generateMatrix(unsigned int sz1, unsigned int sz2)
66 {
67  vpMatrix M(sz1, sz2);
68 
69  for (unsigned int i = 0; i < M.getRows(); i++) {
70  for (unsigned int j = 0; j < M.getCols(); j++) {
71  M[i][j] = i * M.getCols() + j;
72  }
73  }
74 
75  return M;
76 }
77 
78 vpMatrix generateMatrixTranspose(unsigned int sz1, unsigned int sz2)
79 {
80  vpMatrix M(sz2, sz1);
81 
82  for (unsigned int j = 0; j < M.getCols(); j++) {
83  for (unsigned int i = 0; i < M.getRows(); i++) {
84  M[i][j] = j * M.getRows() + i;
85  }
86  }
87 
88  return M;
89 }
90 
91 vpMatrix transposeIterateSrc(const vpMatrix &A)
92 {
93  vpMatrix At;
94 
95  At.resize(A.getCols(), A.getRows(), false, false);
96 
97  for (unsigned int i = 0; i < A.getRows(); i++) {
98  double *coli = A[i];
99  for (unsigned int j = 0; j < A.getCols(); j++) {
100  At[j][i] = coli[j];
101  }
102  }
103 
104  return At;
105 }
106 
107 vpMatrix transposeIterateDst(const vpMatrix &A)
108 {
109  vpMatrix At;
110 
111  At.resize(A.getCols(), A.getRows(), false, false);
112 
113  for (unsigned int j = 0; j < A.getCols(); j++) {
114  double *coli = At[j];
115  for (unsigned int i = 0; i < A.getRows(); i++) {
116  coli[i] = A[i][j];
117  }
118  }
119 
120  return At;
121 }
122 
123 vpMatrix transposeTilingSO(const vpMatrix &A, unsigned int tileSize = 16)
124 {
125  vpMatrix At;
126 
127  At.resize(A.getCols(), A.getRows(), false, false);
128 
129  for (unsigned int i = 0; i < A.getRows(); i += tileSize) {
130  for (unsigned int j = 0; j < A.getCols(); j++) {
131  for (unsigned int b = 0; b < tileSize && i + b < A.getRows(); b++) {
132  At[j][i + b] = A[i + b][j];
133  }
134  }
135  }
136 
137  return At;
138 }
139 
140 vpMatrix transposeTiling(const vpMatrix &A, int tileSize = 16)
141 {
142  vpMatrix At;
143 
144  At.resize(A.getCols(), A.getRows(), false, false);
145 
146  const int nrows = static_cast<int>(A.getRows());
147  const int ncols = static_cast<int>(A.getCols());
148 
149  for (int i = 0; i < nrows;) {
150  for (; i <= nrows - tileSize; i += tileSize) {
151  int j = 0;
152  for (; j <= ncols - tileSize; j += tileSize) {
153  for (int k = i; k < i + tileSize; k++) {
154  for (int l = j; l < j + tileSize; l++) {
155  At[l][k] = A[k][l];
156  }
157  }
158  }
159 
160  for (int k = i; k < i + tileSize; k++) {
161  for (int l = j; l < ncols; l++) {
162  At[l][k] = A[k][l];
163  }
164  }
165  }
166 
167  for (; i < nrows; i++) {
168  for (int j = 0; j < ncols; j++) {
169  At[j][i] = A[i][j];
170  }
171  }
172  }
173 
174  return At;
175 }
176 
177 } // namespace
178 
179 TEST_CASE("Benchmark vpMatrix transpose", "[benchmark]")
180 {
181  if (g_runBenchmark) {
182  const std::vector<std::pair<int, int> > sizes = {
183  {701, 1503}, {1791, 837}, {1201, 1201}, {1024, 1024}, {2000, 2000}, {10, 6}, {25, 6}, {100, 6}, {200, 6},
184  {500, 6}, {1000, 6}, {1500, 6}, {2000, 6}, {6, 10}, {6, 25}, {6, 100}, {6, 200}, {6, 500},
185  {6, 1000}, {6, 1500}, {6, 2000}, {640, 1000}, {800, 640}, {640, 500}, {500, 640}, {640, 837} };
186 
187  for (auto sz : sizes) {
188  vpMatrix M = generateMatrix(sz.first, sz.second);
189  vpMatrix Mt_true = generateMatrixTranspose(sz.first, sz.second);
190 
191  std::ostringstream oss;
192  oss << sz.first << "x" << sz.second;
193  oss << " - M.t()";
194  BENCHMARK(oss.str().c_str())
195  {
196  vpMatrix Mt = M.t();
197  REQUIRE(Mt == Mt_true);
198  return Mt;
199  };
200 
201  oss.str("");
202  oss << sz.first << "x" << sz.second;
203  oss << " - transposeIterateSrc(M)";
204  BENCHMARK(oss.str().c_str())
205  {
206  vpMatrix Mt = transposeIterateSrc(M);
207  REQUIRE(Mt == Mt_true);
208  return Mt;
209  };
210 
211  oss.str("");
212  oss << sz.first << "x" << sz.second;
213  oss << " - transposeIterateDst(M)";
214  BENCHMARK(oss.str().c_str())
215  {
216  vpMatrix Mt = transposeIterateDst(M);
217  REQUIRE(Mt == Mt_true);
218  return Mt;
219  };
220 
221  oss.str("");
222  oss << sz.first << "x" << sz.second;
223  oss << " - transposeTilingSO(M, tileSize=" << g_tileSize << ")";
224  BENCHMARK(oss.str().c_str())
225  {
226  vpMatrix Mt = transposeTilingSO(M, g_tileSize);
227  REQUIRE(Mt == Mt_true);
228  return Mt;
229  };
230 
231  oss.str("");
232  oss << sz.first << "x" << sz.second;
233  oss << " - transposeTiling(M, tileSize=" << g_tileSize << ")";
234  BENCHMARK(oss.str().c_str())
235  {
236  vpMatrix Mt = transposeTiling(M, g_tileSize);
237  REQUIRE(Mt == Mt_true);
238  return Mt;
239  };
240 
241 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
242  cv::Mat matM(sz.first, sz.second, CV_64FC1);
243 
244  for (unsigned int i = 0; i < M.getRows(); i++) {
245  for (unsigned int j = 0; j < M.getCols(); j++) {
246  matM.at<double>(i, j) = M[i][j];
247  }
248  }
249 
250  oss.str("");
251  oss << sz.first << "x" << sz.second;
252  oss << " - OpenCV";
253  BENCHMARK(oss.str().c_str())
254  {
255  cv::Mat matMt = matM.t();
256  return matMt;
257  };
258 #endif
259 
260 #ifdef VISP_HAVE_EIGEN3
261  Eigen::MatrixXd eigenM(sz.first, sz.second);
262 
263  for (unsigned int i = 0; i < M.getRows(); i++) {
264  for (unsigned int j = 0; j < M.getCols(); j++) {
265  eigenM(i, j) = M[i][j];
266  }
267  }
268 
269  oss.str("");
270  oss << sz.first << "x" << sz.second;
271  oss << " - Eigen";
272  BENCHMARK(oss.str().c_str())
273  {
274  Eigen::MatrixXd eigenMt = eigenM.transpose();
275  return eigenMt;
276  };
277 #endif
278  }
279  }
280  else {
281  vpMatrix M = generateMatrix(11, 17);
282  vpMatrix Mt_true = generateMatrixTranspose(11, 17);
283 
284  vpMatrix Mt = M.t();
285  REQUIRE(Mt == Mt_true);
286  }
287 }
288 
289 int main(int argc, char *argv[])
290 {
291  Catch::Session session; // There must be exactly one instance
292 
293  // Build a new parser on top of Catch's
294  using namespace Catch::clara;
295  auto cli = session.cli() // Get Catch's composite command line parser
296  | Opt(g_runBenchmark) // bind variable to a new option, with a hint string
297  ["--benchmark"] // the option names it will respond to
298  ("run benchmark?") // description string for the help output
299  | Opt(g_tileSize, "tileSize")["--tileSize"]("Tile size?");
300 
301 // Now pass the new composite back to Catch so it uses that
302  session.cli(cli);
303 
304  // Let Catch (using Clara) parse the command line
305  session.applyCommandLine(argc, argv);
306 
307  int numFailed = session.run();
308 
309  // numFailed is clamped to 255 as some unices only use the lower 8 bits.
310  // This clamping has already been applied, so just return it here
311  // You can also do any post run clean-up here
312  return numFailed;
313 }
314 #else
315 #include <iostream>
316 
317 int main() { return EXIT_SUCCESS; }
318 #endif
unsigned int getCols() const
Definition: vpArray2D.h:337
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:362
unsigned int getRows() const
Definition: vpArray2D.h:347
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
vpMatrix transpose() const
vpMatrix t() const