Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
bench-reporter.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 2; coding: utf-8 -*- */
2 /*
3  Copyright (C) 2008 Kouhei Sutou <kou@cozmixng.org>
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 version 2.1 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include <string.h>
20 
21 #include "bench-reporter.h"
22 
23 typedef struct _BenchItem BenchItem;
24 struct _BenchItem
25 {
26  gchar *label;
27  gint n;
31  gpointer data;
32 };
33 
34 static BenchItem *
35 bench_item_new(const gchar *label, gint n,
36  BenchSetupFunc bench_setup,
37  BenchFunc bench,
38  BenchTeardownFunc bench_teardown,
39  gpointer data)
40 {
41  BenchItem *item;
42 
43  item = g_slice_new(BenchItem);
44 
45  item->label = g_strdup(label);
46  item->n = n;
47  item->bench_setup = bench_setup;
48  item->bench = bench;
49  item->bench_teardown = bench_teardown;
50  item->data = data;
51 
52  return item;
53 }
54 
55 static void
56 bench_item_free(BenchItem *item)
57 {
58  if (item->label)
59  g_free(item->label);
60 
61  g_slice_free(BenchItem, item);
62 }
63 
64 #define BENCH_REPORTER_GET_PRIVATE(obj) \
65  (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
66  BENCH_TYPE_REPORTER, \
67  BenchReporterPrivate))
68 
71 {
72  GList *items;
73 };
74 
75 G_DEFINE_TYPE(BenchReporter, bench_reporter, G_TYPE_OBJECT)
76 
77 static void dispose (GObject *object);
78 
79 static void
80 bench_reporter_class_init(BenchReporterClass *klass)
81 {
82  GObjectClass *gobject_class;
83 
84  gobject_class = G_OBJECT_CLASS(klass);
85 
86  gobject_class->dispose = dispose;
87 
88  g_type_class_add_private(gobject_class, sizeof(BenchReporterPrivate));
89 }
90 
91 static void
92 bench_reporter_init(BenchReporter *reporter)
93 {
95 
96  priv = BENCH_REPORTER_GET_PRIVATE(reporter);
97 
98  priv->items = NULL;
99 }
100 
101 static void
102 dispose(GObject *object)
103 {
104  BenchReporterPrivate *priv;
105 
106  priv = BENCH_REPORTER_GET_PRIVATE(object);
107 
108  if (priv->items) {
109  g_list_foreach(priv->items, (GFunc)bench_item_free, NULL);
110  g_list_free(priv->items);
111  priv->items = NULL;
112  }
113 
114  G_OBJECT_CLASS(bench_reporter_parent_class)->dispose(object);
115 }
116 
119 {
120  return g_object_new(BENCH_TYPE_REPORTER, NULL);
121 }
122 
123 void
125  const gchar *label, gint n,
126  BenchSetupFunc bench_setup,
127  BenchFunc bench,
128  BenchTeardownFunc bench_teardown,
129  gpointer data)
130 {
131  BenchReporterPrivate *priv;
132 
133  priv = BENCH_REPORTER_GET_PRIVATE(reporter);
134 
135  priv->items = g_list_append(priv->items, bench_item_new(label, n,
136  bench_setup,
137  bench,
138  bench_teardown,
139  data));
140 }
141 
142 #define INDENT " "
143 
144 static void
145 print_header(BenchReporterPrivate *priv, gint max_label_length)
146 {
147  gint n_spaces;
148 
149  g_print(INDENT);
150  for (n_spaces = max_label_length + strlen(": ");
151  n_spaces > 0;
152  n_spaces--) {
153  g_print(" ");
154  }
155  g_print("(time)\n");
156 }
157 
158 static void
159 print_label(BenchReporterPrivate *priv, BenchItem *item, gint max_label_length)
160 {
161  gint n_left_spaces;
162 
163  g_print(INDENT);
164  if (item->label) {
165  n_left_spaces = max_label_length - strlen(item->label);
166  } else {
167  n_left_spaces = max_label_length;
168  }
169  for (; n_left_spaces > 0; n_left_spaces--) {
170  g_print(" ");
171  }
172  if (item->label)
173  g_print("%s", item->label);
174  g_print(": ");
175 }
176 
177 static void
178 report_elapsed(gdouble elapsed_time)
179 {
180  gdouble one_second = 1.0;
181  gdouble one_millisecond = one_second / 1000.0;
182  gdouble one_microsecond = one_millisecond / 1000.0;
183 
184  if (elapsed_time < one_microsecond) {
185  g_print("(%.8fms)", elapsed_time * 1000.0);
186  } else if (elapsed_time < one_millisecond) {
187  g_print("(%.4fms)", elapsed_time * 1000.0);
188  } else {
189  g_print("(%.4fs)", elapsed_time);
190  }
191  g_print("\n");
192 }
193 
194 static void
195 run_item(BenchReporterPrivate *priv, BenchItem *item, gint max_label_length)
196 {
197  GTimer *timer;
198  gint i;
199 
200  print_label(priv, item, max_label_length);
201 
202  timer = g_timer_new();
203  g_timer_stop(timer);
204  g_timer_reset(timer);
205  for (i = 0; i < item->n; i++) {
206  if (item->bench_setup)
207  item->bench_setup(item->data);
208  g_timer_continue(timer);
209  item->bench(item->data);
210  g_timer_stop(timer);
211  if (item->bench_teardown)
212  item->bench_teardown(item->data);
213  }
214 
215  report_elapsed(g_timer_elapsed(timer, NULL));
216 
217  g_timer_destroy(timer);
218 }
219 
220 void
222 {
223  BenchReporterPrivate *priv;
224  GList *node;
225  gint max_label_length = 0;
226 
227  priv = BENCH_REPORTER_GET_PRIVATE(reporter);
228  for (node = priv->items; node; node = g_list_next(node)) {
229  BenchItem *item = node->data;
230 
231  if (item->label)
232  max_label_length = MAX(max_label_length, strlen(item->label));
233  }
234 
235  print_header(priv, max_label_length);
236  for (node = priv->items; node; node = g_list_next(node)) {
237  BenchItem *item = node->data;
238 
239  run_item(priv, item, max_label_length);
240  }
241 }