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