Visual Servoing Platform  version 3.4.1 under development (2021-10-17)
perfMatrixTranspose.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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 bool g_runBenchmark = false;
56 int g_tileSize = 16;
57 
58 vpMatrix generateMatrix(unsigned int sz1, unsigned int sz2)
59 {
60  vpMatrix M(sz1, sz2);
61 
62  for (unsigned int i = 0; i < M.getRows(); i++) {
63  for (unsigned int j = 0; j < M.getCols(); j++) {
64  M[i][j] = i * M.getCols() + j;
65  }
66  }
67 
68  return M;
69 }
70 
71 vpMatrix generateMatrixTranspose(unsigned int sz1, unsigned int sz2)
72 {
73  vpMatrix M(sz2, sz1);
74 
75  for (unsigned int j = 0; j < M.getCols(); j++) {
76  for (unsigned int i = 0; i < M.getRows(); i++) {
77  M[i][j] = j * M.getRows() + i;
78  }
79  }
80 
81  return M;
82 }
83 
84 vpMatrix transposeIterateSrc(const vpMatrix& A)
85 {
86  vpMatrix At;
87 
88  At.resize(A.getCols(), A.getRows(), false, false);
89 
90  for (unsigned int i = 0; i < A.getRows(); i++) {
91  double *coli = A[i];
92  for (unsigned int j = 0; j < A.getCols(); j++) {
93  At[j][i] = coli[j];
94  }
95  }
96 
97  return At;
98 }
99 
100 vpMatrix transposeIterateDst(const vpMatrix& A)
101 {
102  vpMatrix At;
103 
104  At.resize(A.getCols(), A.getRows(), false, false);
105 
106  for (unsigned int j = 0; j < A.getCols(); j++) {
107  double *coli = At[j];
108  for (unsigned int i = 0; i < A.getRows(); i++) {
109  coli[i] = A[i][j];
110  }
111  }
112 
113  return At;
114 }
115 
116 vpMatrix transposeTilingSO(const vpMatrix& A, unsigned int tileSize=16)
117 {
118  vpMatrix At;
119 
120  At.resize(A.getCols(), A.getRows(), false, false);
121 
122  for (unsigned int i = 0; i < A.getRows(); i += tileSize) {
123  for (unsigned int j = 0; j < A.getCols(); j++) {
124  for (unsigned int b = 0; b < tileSize && i + b < A.getRows(); b++) {
125  At[j][i + b] = A[i + b][j];
126  }
127  }
128  }
129 
130  return At;
131 }
132 
133 vpMatrix transposeTiling(const vpMatrix& A, int tileSize = 16)
134 {
135  vpMatrix At;
136 
137  At.resize(A.getCols(), A.getRows(), false, false);
138 
139  const int nrows = static_cast<int>(A.getRows());
140  const int ncols = static_cast<int>(A.getCols());
141 
142  for (int i = 0; i < nrows;) {
143  for (; i <= nrows - tileSize; i += tileSize) {
144  int j = 0;
145  for (; j <= ncols - tileSize; j += tileSize) {
146  for (int k = i; k < i + tileSize; k++) {
147  for (int l = j; l < j + tileSize; l++) {
148  At[l][k] = A[k][l];
149  }
150  }
151  }
152 
153  for (int k = i; k < i + tileSize; k++) {
154  for (int l = j; l < ncols; l++) {
155  At[l][k] = A[k][l];
156  }
157  }
158  }
159 
160  for (; i < nrows; i++) {
161  for (int j = 0; j < ncols; j++) {
162  At[j][i] = A[i][j];
163  }
164  }
165  }
166 
167  return At;
168 }
169 
170 }
171 
172 TEST_CASE("Benchmark vpMatrix transpose", "[benchmark]") {
173  if (g_runBenchmark) {
174  const std::vector<std::pair<int, int>> sizes = { {701, 1503}, {1791, 837}, {1201, 1201}, {1024, 1024}, {2000, 2000},
175  {10, 6}, {25, 6}, {100, 6}, {200, 6}, {500, 6}, {1000, 6}, {1500, 6}, {2000, 6},
176  {6, 10}, {6, 25}, {6, 100}, {6, 200}, {6, 500}, {6, 1000}, {6, 1500}, {6, 2000},
177  {640, 1000}, {800, 640}, {640, 500}, {500, 640}, {640, 837}
178  };
179 
180  for (auto sz : sizes) {
181  vpMatrix M = generateMatrix(sz.first, sz.second);
182  vpMatrix Mt_true = generateMatrixTranspose(sz.first, sz.second);
183 
184  std::ostringstream oss;
185  oss << sz.first << "x" << sz.second;
186  oss << " - M.t()";
187  BENCHMARK(oss.str().c_str()) {
188  vpMatrix Mt = M.t();
189  REQUIRE(Mt == Mt_true);
190  return Mt;
191  };
192 
193  oss.str("");
194  oss << sz.first << "x" << sz.second;
195  oss << " - transposeIterateSrc(M)";
196  BENCHMARK(oss.str().c_str()) {
197  vpMatrix Mt = transposeIterateSrc(M);
198  REQUIRE(Mt == Mt_true);
199  return Mt;
200  };
201 
202  oss.str("");
203  oss << sz.first << "x" << sz.second;
204  oss << " - transposeIterateDst(M)";
205  BENCHMARK(oss.str().c_str()) {
206  vpMatrix Mt = transposeIterateDst(M);
207  REQUIRE(Mt == Mt_true);
208  return Mt;
209  };
210 
211  oss.str("");
212  oss << sz.first << "x" << sz.second;
213  oss << " - transposeTilingSO(M, tileSize=" << g_tileSize << ")";
214  BENCHMARK(oss.str().c_str()) {
215  vpMatrix Mt = transposeTilingSO(M, g_tileSize);
216  REQUIRE(Mt == Mt_true);
217  return Mt;
218  };
219 
220  oss.str("");
221  oss << sz.first << "x" << sz.second;
222  oss << " - transposeTiling(M, tileSize=" << g_tileSize << ")";
223  BENCHMARK(oss.str().c_str()) {
224  vpMatrix Mt = transposeTiling(M, g_tileSize);
225  REQUIRE(Mt == Mt_true);
226  return Mt;
227  };
228 
229 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
230  cv::Mat matM(sz.first, sz.second, CV_64FC1);
231 
232  for (unsigned int i = 0; i < M.getRows(); i++) {
233  for (unsigned int j = 0; j < M.getCols(); j++) {
234  matM.at<double>(i, j) = M[i][j];
235  }
236  }
237 
238  oss.str("");
239  oss << sz.first << "x" << sz.second;
240  oss << " - OpenCV";
241  BENCHMARK(oss.str().c_str()) {
242  cv::Mat matMt = matM.t();
243  return matMt;
244  };
245 #endif
246 
247 #ifdef VISP_HAVE_EIGEN3
248  Eigen::MatrixXd eigenM(sz.first, sz.second);
249 
250  for (unsigned int i = 0; i < M.getRows(); i++) {
251  for (unsigned int j = 0; j < M.getCols(); j++) {
252  eigenM(i, j) = M[i][j];
253  }
254  }
255 
256  oss.str("");
257  oss << sz.first << "x" << sz.second;
258  oss << " - Eigen";
259  BENCHMARK(oss.str().c_str()) {
260  Eigen::MatrixXd eigenMt = eigenM.transpose();
261  return eigenMt;
262  };
263 #endif
264  }
265  } else {
266  vpMatrix M = generateMatrix(11, 17);
267  vpMatrix Mt_true = generateMatrixTranspose(11, 17);
268 
269  vpMatrix Mt = M.t();
270  REQUIRE(Mt == Mt_true);
271  }
272 }
273 
274 int main(int argc, char *argv[])
275 {
276  Catch::Session session; // There must be exactly one instance
277 
278  // Build a new parser on top of Catch's
279  using namespace Catch::clara;
280  auto cli = session.cli() // Get Catch's composite command line parser
281  | Opt(g_runBenchmark) // bind variable to a new option, with a hint string
282  ["--benchmark"] // the option names it will respond to
283  ("run benchmark?") // description string for the help output
284  | Opt(g_tileSize, "tileSize")
285  ["--tileSize"]
286  ("Tile size?");
287 
288  // Now pass the new composite back to Catch so it uses that
289  session.cli(cli);
290 
291  // Let Catch (using Clara) parse the command line
292  session.applyCommandLine(argc, argv);
293 
294  int numFailed = session.run();
295 
296  // numFailed is clamped to 255 as some unices only use the lower 8 bits.
297  // This clamping has already been applied, so just return it here
298  // You can also do any post run clean-up here
299  return numFailed;
300 }
301 #else
302 #include <iostream>
303 
304 int main()
305 {
306  return 0;
307 }
308 #endif
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:153
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:304
unsigned int getRows() const
Definition: vpArray2D.h:289
unsigned int getCols() const
Definition: vpArray2D.h:279
vpMatrix t() const
Definition: vpMatrix.cpp:464
vpMatrix transpose() const
Definition: vpMatrix.cpp:474