1 | /* FriBidi |
2 | * fribidi-benchmark.c - command line benchmark tool for libfribidi |
3 | * |
4 | * Authors: |
5 | * Behdad Esfahbod, 2001, 2002, 2004 |
6 | * Dov Grobgeld, 1999, 2000 |
7 | * |
8 | * Copyright (C) 2004 Sharif FarsiWeb, Inc |
9 | * Copyright (C) 2001,2002 Behdad Esfahbod |
10 | * Copyright (C) 1999,2000 Dov Grobgeld |
11 | * |
12 | * This library is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU Lesser General Public |
14 | * License as published by the Free Software Foundation; either |
15 | * version 2.1 of the License, or (at your option) any later version. |
16 | * |
17 | * This library is distributed in the hope that it will be useful, |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
20 | * Lesser General Public License for more details. |
21 | * |
22 | * You should have received a copy of the GNU Lesser General Public License |
23 | * along with this library, in a file named COPYING; if not, write to the |
24 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
25 | * Boston, MA 02110-1301, USA |
26 | * |
27 | * For licensing issues, contact <fribidi.license@gmail.com>. |
28 | */ |
29 | |
30 | #include <common.h> |
31 | |
32 | #include <fribidi.h> |
33 | #include <fribidi-deprecated.h> |
34 | |
35 | #include <stdio.h> |
36 | |
37 | #ifdef HAVE_CONFIG_H |
38 | # include <config.h> |
39 | #endif |
40 | |
41 | #ifdef STDC_HEADERS |
42 | # include <stdlib.h> |
43 | # include <stddef.h> |
44 | #else |
45 | # if HAVE_STDLIB_H |
46 | # include <stdlib.h> |
47 | # endif |
48 | #endif |
49 | #ifdef HAVE_STRING_H |
50 | # if !STDC_HEADERS && HAVE_MEMORY_H |
51 | # include <memory.h> |
52 | # endif |
53 | # include <string.h> |
54 | #endif |
55 | #ifdef HAVE_STRINGS_H |
56 | # include <strings.h> |
57 | #endif |
58 | #ifdef HAVE_SYS_TIMES_H |
59 | # include <sys/times.h> |
60 | #endif |
61 | #ifdef _WIN32 |
62 | #include <windows.h> |
63 | #endif /* _WIN32 */ |
64 | |
65 | #include "getopt.h" |
66 | |
67 | #define appname "fribidi_benchmark" |
68 | |
69 | #define MAX_STR_LEN 1000 |
70 | #define NUM_ITER 2000 |
71 | |
72 | static void |
73 | die2 ( |
74 | const char *fmt, |
75 | const char *arg |
76 | ) |
77 | { |
78 | fprintf (stderr, format: "%s: " , appname); |
79 | if (fmt) |
80 | fprintf (stderr, format: fmt, arg); |
81 | fprintf (stderr, format: "Try `%s --help' for more information.\n" , appname); |
82 | exit (status: -1); |
83 | } |
84 | |
85 | #define TEST_STRING \ |
86 | "a THE QUICK -123,456 (FOX JUMPS ) DOG the quick !1@7#4&5^ over the dog " \ |
87 | "123,456 OVER THE 5%+ 4.0 LAZY" |
88 | #define TEST_STRING_EXPLICIT \ |
89 | "this is _LJUST_o a _lsimple _Rte%ST_o th_oat HAS A _LPDF missing" \ |
90 | "AnD hOw_L AbOuT, 123,987 tHiS_o a GO_oOD - _L_oTE_oST. " \ |
91 | "here_L is_o_o_o _R a good one_o And _r 123,987_LT_oHE_R next_o oNE:" \ |
92 | "_R_r and the last _LONE_o IS THE _rbest _lONE and" \ |
93 | "a _L_L_L_LL_L_L_L_L_L_L_L_L_Rbug_o_o_o_o_o_o" \ |
94 | "_R_r and the last _LONE_o IS THE _rbest _lONE and" \ |
95 | "A REAL BIG_l_o BUG! _L _l_r_R_L_laslaj siw_o_Rlkj sslk" \ |
96 | "a _L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_L_Rbug" \ |
97 | "here_L is_o_o_o _R ab one_o _r 123,987_LT_oHE_R t_o oNE:" \ |
98 | |
99 | static void |
100 | help ( |
101 | void |
102 | ) |
103 | { |
104 | printf |
105 | (format: "Usage: " appname " [OPTION]...\n" |
106 | "A program for benchmarking the speed of the " FRIBIDI_NAME |
107 | " library.\n" "\n" |
108 | " -h, --help Display this information and exit\n" |
109 | " -V, --version Display version information and exit\n" |
110 | " -n, --niter N Number of iterations. Default is %d.\n" |
111 | "\nReport bugs online at\n<" FRIBIDI_BUGREPORT ">.\n" , NUM_ITER); |
112 | exit (status: 0); |
113 | } |
114 | |
115 | static void |
116 | version ( |
117 | void |
118 | ) |
119 | { |
120 | printf (appname " %s" , fribidi_version_info); |
121 | exit (status: 0); |
122 | } |
123 | |
124 | static double |
125 | utime ( |
126 | void |
127 | ) |
128 | { |
129 | #ifdef _WIN32 |
130 | FILETIME creationTime, exitTime, kernelTime, userTime; |
131 | HANDLE currentProcess = GetCurrentProcess(); |
132 | if (GetProcessTimes(currentProcess, &creationTime, &exitTime, &kernelTime, &userTime)) |
133 | { |
134 | unsigned __int64 myTime = userTime.dwHighDateTime; |
135 | myTime = (myTime << 32) | userTime.dwLowDateTime; |
136 | return 1e-7 * myTime; |
137 | } |
138 | else |
139 | return 0.0; |
140 | #else /* !_WIN32 */ |
141 | #ifdef HAVE_SYS_TIMES_H |
142 | struct tms tb; |
143 | times (buffer: &tb); |
144 | return 0.01 * tb.tms_utime; |
145 | #else |
146 | #warning Please fill in here to use other functions for determining time. |
147 | return 0.0; |
148 | #endif |
149 | #endif |
150 | } |
151 | |
152 | static void |
153 | benchmark ( |
154 | const char *S_, |
155 | int niter |
156 | ) |
157 | { |
158 | int len, i; |
159 | FriBidiChar us[MAX_STR_LEN], out_us[MAX_STR_LEN]; |
160 | FriBidiStrIndex positionLtoV[MAX_STR_LEN], positionVtoL[MAX_STR_LEN]; |
161 | FriBidiLevel embedding_list[MAX_STR_LEN]; |
162 | FriBidiParType base; |
163 | double time0, time1; |
164 | |
165 | { |
166 | int j; |
167 | len = strlen (s: S_); |
168 | for (i = 0, j = 0; i < len; i++) |
169 | { |
170 | if (S_[i] == '_') |
171 | switch (S_[++i]) |
172 | { |
173 | case '>': |
174 | us[j++] = FRIBIDI_CHAR_LRM; |
175 | break; |
176 | case '<': |
177 | us[j++] = FRIBIDI_CHAR_RLM; |
178 | break; |
179 | case 'l': |
180 | us[j++] = FRIBIDI_CHAR_LRE; |
181 | break; |
182 | case 'r': |
183 | us[j++] = FRIBIDI_CHAR_RLE; |
184 | break; |
185 | case 'L': |
186 | us[j++] = FRIBIDI_CHAR_LRO; |
187 | break; |
188 | case 'R': |
189 | us[j++] = FRIBIDI_CHAR_RLO; |
190 | break; |
191 | case 'o': |
192 | us[j++] = FRIBIDI_CHAR_PDF; |
193 | break; |
194 | case '_': |
195 | us[j++] = '_'; |
196 | break; |
197 | default: |
198 | us[j++] = '_'; |
199 | i--; |
200 | break; |
201 | } |
202 | else |
203 | us[j++] = S_[i]; |
204 | if (us[j] >= 'A' && us[j] <= 'F') |
205 | us[j] += FRIBIDI_CHAR_ARABIC_ALEF - 'A'; |
206 | else if (us[j] >= 'G' && us[j] <= 'Z') |
207 | us[j] += FRIBIDI_CHAR_HEBREW_ALEF - 'G'; |
208 | else if (us[j] >= '6' && us[j] <= '9') |
209 | us[j] += FRIBIDI_CHAR_ARABIC_ZERO - '0'; |
210 | } |
211 | len = j; |
212 | } |
213 | |
214 | /* Start timer */ |
215 | time0 = utime (); |
216 | |
217 | for (i = 0; i < niter; i++) |
218 | { |
219 | /* Create a bidi string */ |
220 | base = FRIBIDI_PAR_ON; |
221 | FRIBIDI_BEGIN_IGNORE_DEPRECATIONS |
222 | if (!fribidi_log2vis (str: us, len, pbase_dir: &base, |
223 | /* output */ |
224 | visual_str: out_us, positions_L_to_V: positionVtoL, positions_V_to_L: positionLtoV, |
225 | embedding_levels: embedding_list)) |
226 | die2 |
227 | (fmt: "something failed in fribidi_log2vis.\n" |
228 | "perhaps memory allocation failure." , NULL); |
229 | FRIBIDI_END_IGNORE_DEPRECATIONS |
230 | } |
231 | |
232 | /* stop timer */ |
233 | time1 = utime (); |
234 | |
235 | /* output result */ |
236 | printf (format: "Length = %d\n" , len); |
237 | printf (format: "Iterations = %d\n" , niter); |
238 | printf (format: "%d len*iterations in %f seconds\n" , len * niter, time1 - time0); |
239 | printf (format: "= %.0f kilo.length.iterations/second\n" , |
240 | 1.0 * len * niter / 1000 / (time1 - time0)); |
241 | |
242 | return; |
243 | } |
244 | |
245 | int |
246 | main ( |
247 | int argc, |
248 | char *argv[] |
249 | ) |
250 | { |
251 | int niter = NUM_ITER; |
252 | |
253 | /* Parse the command line */ |
254 | argv[0] = appname; |
255 | while (1) |
256 | { |
257 | int option_index = 0, c; |
258 | static struct option long_options[] = { |
259 | {"help" , 0, 0, 'h'}, |
260 | {"version" , 0, 0, 'V'}, |
261 | {"niter" , 0, 0, 'n'}, |
262 | {0, 0, 0, 0} |
263 | }; |
264 | |
265 | c = getopt_long (argc: argc, argv: argv, shortopts: "hVn:" , longopts: long_options, longind: &option_index); |
266 | if (c == -1) |
267 | break; |
268 | |
269 | switch (c) |
270 | { |
271 | case 0: |
272 | break; |
273 | case 'h': |
274 | help (); |
275 | break; |
276 | case 'V': |
277 | version (); |
278 | break; |
279 | case 'n': |
280 | niter = atoi (nptr: optarg); |
281 | if (niter <= 0) |
282 | die2 (fmt: "invalid number of iterations `%s'\n" , arg: optarg); |
283 | break; |
284 | case ':': |
285 | case '?': |
286 | die2 (NULL, NULL); |
287 | break; |
288 | default: |
289 | break; |
290 | } |
291 | } |
292 | |
293 | printf (format: "* Without explicit marks:\n" ); |
294 | benchmark (TEST_STRING, niter); |
295 | printf (format: "\n" ); |
296 | printf (format: "* With explicit marks:\n" ); |
297 | benchmark (TEST_STRING_EXPLICIT, niter); |
298 | |
299 | return 0; |
300 | } |
301 | |
302 | /* Editor directions: |
303 | * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent |
304 | */ |
305 | |