1 | /* GLIB - Library of useful routines for C programming |
2 | * |
3 | * Copyright (C) 2010 Mikhail Zabaluev <mikhail.zabaluev@gmail.com> |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2.1 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | #include <string.h> |
20 | |
21 | #include <glib.h> |
22 | |
23 | #define NUM_ITERATIONS 500000 |
24 | |
25 | static const char str_ascii[] = |
26 | "The quick brown fox jumps over the lazy dog" ; |
27 | |
28 | static const gchar str_latin1[] = |
29 | "Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich" ; |
30 | |
31 | /* Energizing GOELRO-talk in Russian, used by KDE */ |
32 | static const char str_cyrillic[] = |
33 | "Широкая электрификация южных губерний даст мощный толчок подъёму " |
34 | "сельского хозяйства." ; |
35 | |
36 | /* First sentence from the Wikipedia article: |
37 | * http://zh.wikipedia.org/w/index.php?title=%E6%B1%89%E5%AD%97&oldid=13053137 */ |
38 | static const char str_han[] = |
39 | "漢字,亦稱中文字、中国字,在台灣又被稱為國字,是漢字文化圈廣泛使用的一種文字,屬於表意文字的詞素音節文字" ; |
40 | |
41 | typedef int (* GrindFunc) (const char *, gsize); |
42 | |
43 | #define GRIND_LOOP_BEGIN \ |
44 | { \ |
45 | int i; \ |
46 | for (i = 0; i < NUM_ITERATIONS; i++) |
47 | |
48 | #define GRIND_LOOP_END \ |
49 | } |
50 | |
51 | static int |
52 | grind_get_char (const char *str, gsize len) |
53 | { |
54 | gunichar acc = 0; |
55 | GRIND_LOOP_BEGIN |
56 | { |
57 | const char *p = str; |
58 | while (*p) |
59 | { |
60 | acc += g_utf8_get_char (p); |
61 | p = g_utf8_next_char (p); |
62 | } |
63 | } |
64 | GRIND_LOOP_END; |
65 | return acc; |
66 | } |
67 | |
68 | static int |
69 | grind_get_char_validated (const char *str, gsize len) |
70 | { |
71 | gunichar acc = 0; |
72 | GRIND_LOOP_BEGIN |
73 | { |
74 | const char *p = str; |
75 | while (*p) |
76 | { |
77 | acc += g_utf8_get_char_validated (p, max_len: -1); |
78 | p = g_utf8_next_char (p); |
79 | } |
80 | } |
81 | GRIND_LOOP_END; |
82 | return acc; |
83 | } |
84 | |
85 | static int |
86 | grind_utf8_to_ucs4 (const char *str, gsize len) |
87 | { |
88 | GRIND_LOOP_BEGIN |
89 | { |
90 | gunichar *ustr; |
91 | ustr = g_utf8_to_ucs4 (str, len: -1, NULL, NULL, NULL); |
92 | g_free (mem: ustr); |
93 | } |
94 | GRIND_LOOP_END; |
95 | return 0; |
96 | } |
97 | |
98 | static int |
99 | grind_get_char_backwards (const char *str, gsize len) |
100 | { |
101 | gunichar acc = 0; |
102 | GRIND_LOOP_BEGIN |
103 | { |
104 | const char *p = str + len; |
105 | do |
106 | { |
107 | p = g_utf8_prev_char (p); |
108 | acc += g_utf8_get_char (p); |
109 | } |
110 | while (p != str); |
111 | } |
112 | GRIND_LOOP_END; |
113 | return acc; |
114 | } |
115 | |
116 | static int |
117 | grind_utf8_to_ucs4_sized (const char *str, gsize len) |
118 | { |
119 | GRIND_LOOP_BEGIN |
120 | { |
121 | gunichar *ustr; |
122 | ustr = g_utf8_to_ucs4 (str, len, NULL, NULL, NULL); |
123 | g_free (mem: ustr); |
124 | } |
125 | GRIND_LOOP_END; |
126 | return 0; |
127 | } |
128 | |
129 | static int |
130 | grind_utf8_to_ucs4_fast (const char *str, gsize len) |
131 | { |
132 | GRIND_LOOP_BEGIN |
133 | { |
134 | gunichar *ustr; |
135 | ustr = g_utf8_to_ucs4_fast (str, len: -1, NULL); |
136 | g_free (mem: ustr); |
137 | } |
138 | GRIND_LOOP_END; |
139 | return 0; |
140 | } |
141 | |
142 | static int |
143 | grind_utf8_to_ucs4_fast_sized (const char *str, gsize len) |
144 | { |
145 | GRIND_LOOP_BEGIN |
146 | { |
147 | gunichar *ustr; |
148 | ustr = g_utf8_to_ucs4_fast (str, len, NULL); |
149 | g_free (mem: ustr); |
150 | } |
151 | GRIND_LOOP_END; |
152 | return 0; |
153 | } |
154 | |
155 | static int |
156 | grind_utf8_validate (const char *str, gsize len) |
157 | { |
158 | GRIND_LOOP_BEGIN |
159 | g_utf8_validate (str, max_len: -1, NULL); |
160 | GRIND_LOOP_END; |
161 | return 0; |
162 | } |
163 | |
164 | static int |
165 | grind_utf8_validate_sized (const char *str, gsize len) |
166 | { |
167 | GRIND_LOOP_BEGIN |
168 | g_utf8_validate (str, max_len: len, NULL); |
169 | GRIND_LOOP_END; |
170 | return 0; |
171 | } |
172 | |
173 | typedef struct _GrindData { |
174 | GrindFunc func; |
175 | const char *str; |
176 | } GrindData; |
177 | |
178 | static void |
179 | perform (gconstpointer data) |
180 | { |
181 | GrindData *gd = (GrindData *) data; |
182 | GrindFunc grind_func = gd->func; |
183 | const char *str = gd->str; |
184 | gsize len; |
185 | gulong bytes_ground; |
186 | gdouble time_elapsed; |
187 | gdouble result; |
188 | |
189 | len = strlen (s: str); |
190 | bytes_ground = (gulong) len * NUM_ITERATIONS; |
191 | |
192 | g_test_timer_start (); |
193 | |
194 | grind_func (str, len); |
195 | |
196 | time_elapsed = g_test_timer_elapsed (); |
197 | |
198 | result = ((gdouble) bytes_ground / time_elapsed) * 1.0e-6; |
199 | |
200 | g_test_maximized_result (maximized_quantity: result, format: "%7.1f MB/s" , result); |
201 | |
202 | g_slice_free (GrindData, gd); |
203 | } |
204 | |
205 | static void |
206 | add_cases(const char *path, GrindFunc func) |
207 | { |
208 | #define ADD_CASE(script) \ |
209 | G_STMT_START { \ |
210 | GrindData *gd; \ |
211 | gchar *full_path; \ |
212 | gd = g_slice_new0(GrindData); \ |
213 | gd->func = func; \ |
214 | gd->str = str_##script; \ |
215 | full_path = g_strdup_printf("%s/" #script, path); \ |
216 | g_test_add_data_func (full_path, gd, perform); \ |
217 | g_free (full_path); \ |
218 | } G_STMT_END |
219 | |
220 | ADD_CASE(ascii); |
221 | ADD_CASE(latin1); |
222 | ADD_CASE(cyrillic); |
223 | ADD_CASE(han); |
224 | |
225 | #undef ADD_CASE |
226 | } |
227 | |
228 | int |
229 | main (int argc, char **argv) |
230 | { |
231 | g_test_init (argc: &argc, argv: &argv, NULL); |
232 | |
233 | if (g_test_perf ()) |
234 | { |
235 | add_cases (path: "/utf8/perf/get_char" , func: grind_get_char); |
236 | add_cases (path: "/utf8/perf/get_char-backwards" , func: grind_get_char_backwards); |
237 | add_cases (path: "/utf8/perf/get_char_validated" , func: grind_get_char_validated); |
238 | add_cases (path: "/utf8/perf/utf8_to_ucs4" , func: grind_utf8_to_ucs4); |
239 | add_cases (path: "/utf8/perf/utf8_to_ucs4-sized" , func: grind_utf8_to_ucs4_sized); |
240 | add_cases (path: "/utf8/perf/utf8_to_ucs4_fast" , func: grind_utf8_to_ucs4_fast); |
241 | add_cases (path: "/utf8/perf/utf8_to_ucs4_fast-sized" , func: grind_utf8_to_ucs4_fast_sized); |
242 | add_cases (path: "/utf8/perf/utf8_validate" , func: grind_utf8_validate); |
243 | add_cases (path: "/utf8/perf/utf8_validate-sized" , func: grind_utf8_validate_sized); |
244 | } |
245 | |
246 | return g_test_run (); |
247 | } |
248 | |