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
die2(const char * fmt,const char * arg)73 die2 (
74   const char *fmt,
75   const char *arg
76 )
77 {
78   fprintf (stderr, "%s: ", appname);
79   if (fmt)
80     fprintf (stderr, fmt, arg);
81   fprintf (stderr, "Try `%s --help' for more information.\n", appname);
82   exit (-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
help(void)100 help (
101   void
102 )
103 {
104   printf
105     ("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 (0);
113 }
114 
115 static void
version(void)116 version (
117   void
118 )
119 {
120   printf (appname " %s", fribidi_version_info);
121   exit (0);
122 }
123 
124 static double
utime(void)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 (&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
benchmark(const char * S_,int niter)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_);
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 (us, len, &base,
223 			    /* output */
224 			    out_us, positionVtoL, positionLtoV,
225 			    embedding_list))
226 	die2
227 	  ("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 ("Length = %d\n", len);
237   printf ("Iterations = %d\n", niter);
238   printf ("%d len*iterations in %f seconds\n", len * niter, time1 - time0);
239   printf ("= %.0f kilo.length.iterations/second\n",
240 	  1.0 * len * niter / 1000 / (time1 - time0));
241 
242   return;
243 }
244 
245 int
main(int argc,char * argv[])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, argv, "hVn:", long_options, &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 (optarg);
281 	  if (niter <= 0)
282 	    die2 ("invalid number of iterations `%s'\n", optarg);
283 	  break;
284 	case ':':
285 	case '?':
286 	  die2 (NULL, NULL);
287 	  break;
288 	default:
289 	  break;
290 	}
291     }
292 
293   printf ("* Without explicit marks:\n");
294   benchmark (TEST_STRING, niter);
295   printf ("\n");
296   printf ("* 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