Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / libreofficekit / qa / tilebench / tilebench.cxx
blob8bb41999f17c8822a449e8e3c199183e1ed8c732
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <assert.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <cmath>
15 #include <vector>
16 #include <fstream>
17 #include <osl/time.h>
19 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
20 #include <LibreOfficeKit/LibreOfficeKitInit.h>
21 #include <LibreOfficeKit/LibreOfficeKit.hxx>
23 using namespace lok;
25 static int help()
27 fprintf( stderr, "Usage: tilebench <absolute-path-to-libreoffice-install> [path to document] [max parts|-1] [max tiles|-1]\n" );
28 fprintf( stderr, "renders a selection of small tiles from the document, checksums them and times the process\n" );
29 return 1;
32 static double getTimeNow()
34 TimeValue aValue;
35 osl_getSystemTime(&aValue);
36 return static_cast<double>(aValue.Seconds) +
37 static_cast<double>(aValue.Nanosec) / (1000*1000*1000);
40 /// Dump an array of RGBA or BGRA to an RGB PPM file.
41 static void dumpTile(const int nWidth, const int nHeight, const int mode, const char* pBuffer)
43 std::ofstream ofs("/tmp/dump_tile.ppm");
44 ofs << "P6\n"
45 << nWidth << " "
46 << nHeight << "\n"
47 << 255 << "\n" ;
49 for (int y = 0; y < nHeight; ++y)
51 const char* row = pBuffer + y * nWidth * 4;
52 for (int x = 0; x < nWidth; ++x)
54 const char* pixel = row + x * 4;
55 if (mode == LOK_TILEMODE_RGBA)
57 ofs.write(pixel, 3); // Skip alpha
59 else if (mode == LOK_TILEMODE_BGRA)
61 const int alpha = *(pixel + 3);
62 char buf[3];
63 if (alpha == 0)
65 buf[0] = 0;
66 buf[1] = 0;
67 buf[2] = 0;
69 else
71 buf[0] = (*(pixel + 2) * 255 + alpha / 2) / alpha;
72 buf[1] = (*(pixel + 1) * 255 + alpha / 2) / alpha;
73 buf[2] = (*(pixel + 0) * 255 + alpha / 2) / alpha;
76 ofs.write(buf, 3);
82 int main( int argc, char* argv[] )
84 static const double origin = getTimeNow();
85 struct TimeRecord {
86 const char *mpName;
87 double mfTime;
89 TimeRecord() : mpName(nullptr), mfTime(getTimeNow()) { }
90 explicit TimeRecord(const char *pName) :
91 mpName(pName), mfTime(getTimeNow())
93 fprintf(stderr, "%3.3fs - %s\n", (mfTime - origin), mpName);
96 std::vector< TimeRecord > aTimes;
97 if( argc < 2 ||
98 ( argc > 1 && ( !strcmp( argv[1], "--help" ) || !strcmp( argv[1], "-h" ) ) ) )
99 return help();
101 if ( argv[1][0] != '/' )
103 fprintf(stderr, "Absolute path required to libreoffice install\n");
104 return 1;
107 aTimes.emplace_back("initialization");
108 // coverity[tainted_string] - build time test tool
109 Office *pOffice = lok_cpp_init(argv[1]);
110 if (pOffice == nullptr)
112 fprintf(stderr, "Failed to initialize Office from %s\n", argv[1]);
113 return 1;
116 aTimes.emplace_back();
118 const int max_parts = (argc > 3 ? atoi(argv[3]) : -1);
119 int max_tiles = (argc > 4 ? atoi(argv[4]) : -1);
120 const bool dump = true;
122 if (argv[2] != nullptr)
124 aTimes.emplace_back("load document");
125 Document *pDocument(pOffice->documentLoad(argv[2]));
126 aTimes.emplace_back();
127 const int mode = pDocument->getTileMode();
129 aTimes.emplace_back("getparts");
130 const int nOriginalPart = (pDocument->getDocumentType() == LOK_DOCTYPE_TEXT ? 1 : pDocument->getPart());
131 // Writer really has 1 part (the full doc).
132 const int nTotalParts = (pDocument->getDocumentType() == LOK_DOCTYPE_TEXT ? 1 : pDocument->getParts());
133 const int nParts = (max_parts < 0 ? nTotalParts : std::min(max_parts, nTotalParts));
134 aTimes.emplace_back();
136 aTimes.emplace_back("get size of parts");
137 long nWidth = 0;
138 long nHeight = 0;
139 for (int n = 0; n < nParts; ++n)
141 const int nPart = (nOriginalPart + n) % nTotalParts;
142 char* pName = pDocument->getPartName(nPart);
143 pDocument->setPart(nPart);
144 pDocument->getDocumentSize(&nWidth, &nHeight);
145 fprintf (stderr, " '%s' -> %ld, %ld\n", pName, nWidth, nHeight);
146 free (pName);
148 aTimes.emplace_back();
150 // Use realistic dimensions, similar to the Online client.
151 long nTilePixelWidth = 512;
152 long nTilePixelHeight = 512;
153 long nTileTwipWidth = 3840;
154 long nTileTwipHeight = 3840;
156 // Estimate the maximum tiles based on the number of parts requested, if Writer.
157 if (pDocument->getDocumentType() == LOK_DOCTYPE_TEXT)
158 max_tiles = static_cast<int>(ceil(max_parts * 16128. / nTilePixelHeight) * ceil(static_cast<double>(nWidth) / nTilePixelWidth));
159 fprintf(stderr, "Parts to render: %d, Total Parts: %d, Max parts: %d, Max tiles: %d\n", nParts, nTotalParts, max_parts, max_tiles);
161 std::vector<unsigned char> vBuffer(nTilePixelWidth * nTilePixelHeight * 4);
162 unsigned char* pPixels = &vBuffer[0];
164 for (int n = 0; n < nParts; ++n)
166 const int nPart = (nOriginalPart + n) % nTotalParts;
167 char* pName = pDocument->getPartName(nPart);
168 pDocument->setPart(nPart);
169 pDocument->getDocumentSize(&nWidth, &nHeight);
170 fprintf (stderr, "render '%s' -> %ld, %ld\n", pName, nWidth, nHeight);
171 free (pName);
173 if (dump || pDocument->getDocumentType() != LOK_DOCTYPE_TEXT)
175 // whole part; meaningful only for non-writer documents.
176 aTimes.emplace_back("render whole part");
177 pDocument->paintTile(pPixels, nTilePixelWidth, nTilePixelHeight,
178 nWidth/2, 2000, 1000, 1000); // not square
179 aTimes.emplace_back();
180 if (dump)
181 dumpTile(nTilePixelWidth, nTilePixelHeight, mode, reinterpret_cast<char*>(pPixels));
184 { // 1:1
185 aTimes.emplace_back("render sub-region at 1:1");
186 // Estimate the maximum tiles based on the number of parts requested, if Writer.
187 int nMaxTiles = max_tiles;
188 int nTiles = 0;
189 for (int nY = 0; nY < nHeight - 1; nY += nTilePixelHeight)
191 for (int nX = 0; nX < nWidth - 1; nX += nTilePixelWidth)
193 if (nMaxTiles >= 0 && nTiles >= nMaxTiles)
195 nY = nHeight;
196 break;
199 pDocument->paintTile(pPixels, nTilePixelWidth, nTilePixelHeight,
200 nX, nY, nTilePixelWidth, nTilePixelHeight);
201 nTiles++;
202 fprintf (stderr, " rendered 1:1 tile %d at %d, %d\n",
203 nTiles, nX, nY);
206 aTimes.emplace_back();
209 { // scaled
210 aTimes.emplace_back("render sub-regions at scale");
211 int nMaxTiles = max_tiles;
212 if (pDocument->getDocumentType() == LOK_DOCTYPE_TEXT)
213 nMaxTiles = static_cast<int>(ceil(max_parts * 16128. / nTileTwipHeight) * ceil(static_cast<double>(nWidth) / nTileTwipWidth));
214 int nTiles = 0;
215 for (int nY = 0; nY < nHeight - 1; nY += nTileTwipHeight)
217 for (int nX = 0; nX < nWidth - 1; nX += nTileTwipWidth)
219 if (nMaxTiles >= 0 && nTiles >= nMaxTiles)
221 nY = nHeight;
222 break;
225 pDocument->paintTile(pPixels, nTilePixelWidth, nTilePixelHeight,
226 nX, nY, nTileTwipWidth, nTileTwipHeight);
227 nTiles++;
228 fprintf (stderr, " rendered scaled tile %d at %d, %d\n",
229 nTiles, nX, nY);
232 aTimes.emplace_back();
236 aTimes.emplace_back("destroy document");
237 delete pDocument;
238 aTimes.emplace_back();
241 delete pOffice;
243 double nTotal = 0.0;
244 fprintf (stderr, "profile run:\n");
245 for (size_t i = 0; i < aTimes.size() - 1; i++)
247 const double nDelta = aTimes[i+1].mfTime - aTimes[i].mfTime;
248 fprintf (stderr, " %s - %2.4f(ms)\n", aTimes[i].mpName, nDelta * 1000.0);
249 if (aTimes[i+1].mpName == nullptr)
250 i++; // skip it.
251 nTotal += nDelta;
253 fprintf (stderr, "Total: %2.4f(s)\n", nTotal);
254 return 0;
257 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */