Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
test-performance.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 2; coding: utf-8 -*- */
2 /*
3  Copyright (C) 2008-2009 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 <groonga.h>
20 
21 #include <cutter.h>
22 
23 #include "../lib/grn-assertions.h"
24 
25 void data_read_write(void);
26 void test_read_write(gconstpointer test_data);
27 
28 typedef struct _grn_test_data
29 {
30  gchar *type_name;
33  gboolean multi_thread;
35 
36 static GList *sub_processes;
37 static grn_test_data *base_data;
38 
39 static grn_ctx *context;
40 static grn_obj *space;
41 static grn_obj *type;
42 static grn_obj *table;
43 static gchar *base_dir;
44 static gchar *env_table_path;
45 static gchar *env_table_type;
46 static gchar *env_multi_thread;
47 static gchar *env_n_processes;
48 static gchar *env_process_number;
49 
50 static grn_test_data *
51 test_data_new(const gchar *type_name, grn_obj_flags flags,
52  gint n_processes, gboolean multi_thread)
53 {
54  grn_test_data *data;
55 
56  data = g_new0(grn_test_data, 1);
57  data->type_name = g_strdup(type_name);
58  data->flags = flags;
59  data->n_processes = n_processes;
60  data->multi_thread = multi_thread;
61 
62  return data;
63 }
64 
65 static void
66 test_data_free(grn_test_data *data)
67 {
68  g_free(data->type_name);
69  g_free(data);
70 }
71 
72 void
73 cut_setup(void)
74 {
75  const gchar *tmp_dir;
76 
77  sub_processes = NULL;
78  base_data = NULL;
79 
80  context = g_new0(grn_ctx, 1);
81  space = NULL;
82  table = NULL;
83 
84 #define SAVE_ENV_VALUE(var_name, macro_name) \
85  env_ ## var_name = g_strdup(g_getenv(GRN_TEST_ENV_ ## macro_name))
86 
87  SAVE_ENV_VALUE(table_path, TABLE_PATH);
88  SAVE_ENV_VALUE(table_type, TABLE_TYPE);
89  SAVE_ENV_VALUE(multi_thread, MULTI_THREAD);
90  SAVE_ENV_VALUE(n_processes, N_PROCESSES);
91  SAVE_ENV_VALUE(process_number, PROCESS_NUMBER);
92 
93 #undef SAVE_ENV_VALUE
94 
95  tmp_dir = grn_test_get_tmp_dir();
96  cut_remove_path(tmp_dir, NULL);
97 
98  base_dir = g_build_filename(tmp_dir, "performance", NULL);
99 
100  g_mkdir_with_parents(base_dir, 0755);
101  cut_assert_path_exist(base_dir);
102 }
103 
104 void
106 {
107  if (sub_processes)
108  g_list_free(sub_processes);
109 
110  if (base_data)
111  test_data_free(base_data);
112 
113  if (context) {
114  if (table)
115  grn_obj_close(context, table);
116  if (space)
117  grn_obj_close(context, space);
118  grn_ctx_fin(context);
119  g_free(context);
120  }
121 
122 #define RESTORE_ENV_VALUE(var_name, macro_name) do \
123  { \
124  if (env_ ## var_name) { \
125  g_setenv(GRN_TEST_ENV_ ## macro_name, env_ ## var_name, TRUE); \
126  g_free(env_ ## var_name); \
127  } else { \
128  g_unsetenv(GRN_TEST_ENV_ ## macro_name); \
129  } \
130  } while(0)
131 
132  RESTORE_ENV_VALUE(table_path, TABLE_PATH);
133  RESTORE_ENV_VALUE(table_type, TABLE_TYPE);
134  RESTORE_ENV_VALUE(multi_thread, MULTI_THREAD);
135  RESTORE_ENV_VALUE(n_processes, N_PROCESSES);
136  RESTORE_ENV_VALUE(process_number, PROCESS_NUMBER);
137 
138 #undef RESTORE_ENV_VALUE
139 
140  if (base_dir) {
141  cut_remove_path(base_dir, NULL);
142  g_free(base_dir);
143  }
144 }
145 
146 static gboolean
147 run(const gchar **test_case_names, const grn_test_data *data)
148 {
149  gint i;
150  const gchar *test_dir;
151  CutSubProcessGroup *group;
152 
153  test_dir = cut_take_string(g_build_filename(grn_test_get_base_dir(),
154  "fixtures",
155  NULL));
156 
157  group = cut_take_new_sub_process_group();
158  for (i = 0; i < data->n_processes; i++) {
159  CutSubProcess *sub_process;
160 
161  sub_process = cut_take_new_sub_process(test_dir);
162  cut_sub_process_set_multi_thread(sub_process, data->multi_thread);
163  cut_sub_process_set_fatal_failures(sub_process, TRUE);
164  cut_sub_process_set_target_test_case_names(sub_process, test_case_names);
165 
166  cut_sub_process_group_add(group, sub_process);
167  if (data->multi_thread)
168  g_setenv(GRN_TEST_ENV_MULTI_THREAD, "TRUE", TRUE);
169  else
170  g_unsetenv(GRN_TEST_ENV_MULTI_THREAD);
171  g_setenv(GRN_TEST_ENV_N_PROCESSES,
172  cut_take_printf("%d", data->n_processes), TRUE);
173  g_setenv(GRN_TEST_ENV_PROCESS_NUMBER, cut_take_printf("%d", i), TRUE);
174  cut_sub_process_run_async(sub_process);
175 
176  sub_processes = g_list_append(sub_processes, sub_process);
177  }
178  return cut_sub_process_group_wait(group);
179 }
180 
181 static gboolean
182 run_test(const gchar **test_case_names, const grn_test_data *data)
183 {
184  const gchar *type_name, *table_name;
185  gchar *path;
186 
188 
190 
191  type_name = "name";
192  type = grn_type_create(context, type_name, strlen(type_name),
193  GRN_OBJ_KEY_UINT, sizeof(grn_id));
194 
195  path = g_build_filename(base_dir, "table", NULL);
196  g_setenv(GRN_TEST_ENV_TABLE_PATH, path, TRUE);
197 
198  table_name = cut_take_printf("%s: performance-read-write", data->type_name);
199  g_setenv(GRN_TEST_ENV_TABLE_TYPE, data->type_name, TRUE);
200  table = grn_table_create(context,
201  table_name, strlen(table_name),
202  path, GRN_OBJ_PERSISTENT | data->flags,
203  type, NULL);
204  g_free(path);
205  cut_assert_not_null(table);
206 
207  return run(test_case_names, data);
208 }
209 
210 
211 static void
212 add_read_write_data(const gchar *type_name, grn_obj_flags flags)
213 {
214  cut_add_data(cut_take_printf("%s - single process - single thread", type_name),
215  test_data_new(type_name, flags, 1, FALSE), test_data_free,
216 
217  cut_take_printf("%s - single process - multi thread", type_name),
218  test_data_new(type_name, flags, 1, TRUE), test_data_free,
219 
220  cut_take_printf("%s - multi process - single thread", type_name),
221  test_data_new(type_name, flags, 10, FALSE), test_data_free,
222 
223  cut_take_printf("%s - multi process - multi thread", type_name),
224  test_data_new(type_name, flags, 10, TRUE), test_data_free);
225 }
226 
227 void
229 {
230  add_read_write_data("hash", GRN_OBJ_TABLE_HASH_KEY);
231  add_read_write_data("patricia tree", GRN_OBJ_TABLE_PAT_KEY);
232 }
233 
234 void
235 test_read_write(gconstpointer test_data)
236 {
237  const grn_test_data *data = test_data;
238  const gchar *test_case_names[] = {"test_read_write", NULL};
239  CutSubProcess *target_sub_process;
240  CutSubProcess *base_sub_process;
241  gdouble target_elapsed, base_elapsed;
242 
243  cut_assert_true(run_test(test_case_names, data));
244  target_sub_process = g_list_last(sub_processes)->data;
245 
246  base_data = test_data_new(cut_take_printf("%s - base", data->type_name),
247  data->flags, 1, FALSE);
248  cut_assert_true(run_test(test_case_names, base_data));
249  base_sub_process = g_list_last(sub_processes)->data;
250 
251  target_elapsed = cut_sub_process_get_total_elapsed(target_sub_process);
252  base_elapsed = cut_sub_process_get_total_elapsed(base_sub_process);
253 
254  /* TODO: should use cut_assert_operator_double() in Cutter 1.0.5 */
255  cut_assert_operator(target_elapsed / (data->multi_thread ? 100 : 1),
256  <,
257  base_elapsed);
258 }