stuff
[oweals/gnunet.git] / src / datastore / perf_plugin_datastore.c
1 /*
2      This file is part of GNUnet.
3      (C) 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /*
21  * @file perf_plugin_datastore.c
22  * @brief Profile database plugin directly, focusing on iterators.
23  * @author Christian Grothoff
24  */
25
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
29 #include "plugin_datastore.h"
30
31 #define VERBOSE GNUNET_YES
32
33 /**
34  * Target datastore size (in bytes).  Realistic sizes are
35  * more like 16 GB (not the default of 16 MB); however,
36  * those take too long to run them in the usual "make check"
37  * sequence.  Hence the value used for shipping is tiny.
38  */
39 #define MAX_SIZE 1024LL * 1024
40 /* * 128 */
41
42 #define ITERATIONS 2
43
44 /**
45  * Number of put operations equivalent to 1/10th of MAX_SIZE
46  */
47 #define PUT_10 (MAX_SIZE / 32 / 1024 / ITERATIONS)
48
49 static unsigned long long stored_bytes;
50
51 static unsigned long long stored_entries;
52
53 static unsigned long long stored_ops;
54
55 static int ok;
56
57 enum RunPhase
58   {
59     RP_DONE = 0,
60     RP_PUT,
61     RP_LP_GET,
62     RP_AE_GET,
63     RP_ZA_GET,
64     RP_MO_GET,
65     RP_AN_GET
66   };
67
68
69 struct CpsRunContext
70 {
71   unsigned int i;
72   struct GNUNET_TIME_Absolute start;
73   struct GNUNET_TIME_Absolute end;
74   struct GNUNET_SCHEDULER_Handle *sched;
75   struct GNUNET_CONFIGURATION_Handle *cfg;
76   struct GNUNET_DATASTORE_PluginFunctions * api;
77   const char *msg;
78   enum RunPhase phase;
79 };
80
81
82              
83 static void
84 putValue (struct GNUNET_DATASTORE_PluginFunctions * api, int i, int k)
85 {
86   char value[65536];
87   size_t size;
88   static GNUNET_HashCode key;
89   static int ic;
90   char *msg;
91
92   /* most content is 32k */
93   size = 32 * 1024;
94
95   if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16) == 0)  /* but some of it is less! */
96     size = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024);
97   size = size - (size & 7);     /* always multiple of 8 */
98
99   /* generate random key */
100   key.bits[0] = (unsigned int) GNUNET_TIME_absolute_get ().value;
101   GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &key);
102   memset (value, i, size);
103   if (i > 255)
104     memset (value, i - 255, size / 2);
105   value[0] = k;
106   msg = NULL;
107   if (GNUNET_OK != api->put (api->cls,
108                              &key, 
109                              size,
110                              value,
111                              i,
112                              GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100),
113                              i,
114                              GNUNET_TIME_relative_to_absolute 
115                              (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
116                                                              60 * 60 * 60 * 1000 +
117                                                              GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000))),
118                              &msg))
119     {
120       fprintf (stderr, "ERROR: `%s'\n", msg);
121       GNUNET_free_non_null (msg);
122       return;
123     }
124   ic++;
125   stored_bytes += size;
126   stored_ops++;
127   stored_entries++;
128 }
129
130 static void
131 test (void *cls,
132       const struct GNUNET_SCHEDULER_TaskContext *tc);
133
134
135 static int
136 iterateDummy (void *cls,
137               void *next_cls,
138               const GNUNET_HashCode * key,
139               uint32_t size,
140               const void *data,
141               uint32_t type,
142               uint32_t priority,
143               uint32_t anonymity,
144               struct GNUNET_TIME_Absolute
145               expiration, 
146               uint64_t uid)
147 {
148   struct CpsRunContext *crc = cls;
149   
150   if (key == NULL)
151     {
152       crc->end = GNUNET_TIME_absolute_get();
153       printf (crc->msg,
154               crc->i,
155               (unsigned long long) (crc->end.value - crc->start.value));
156       if (crc->phase != RP_AN_GET)
157         {
158           crc->phase++;
159         }
160       else
161         {
162           if (crc->i == ITERATIONS)
163             crc->phase = RP_DONE;
164           else
165             crc->phase = RP_PUT;
166         }
167       GNUNET_SCHEDULER_add_after (crc->sched,
168                                   GNUNET_NO,
169                                   GNUNET_SCHEDULER_PRIORITY_KEEP,
170                                   GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
171                                   &test, crc);
172       return GNUNET_OK;
173     }
174   fprintf (stderr, ".");
175   crc->api->next_request (next_cls,
176                           GNUNET_NO);
177   return GNUNET_OK;
178 }
179
180
181
182 /**
183  * Function called when the service shuts
184  * down.  Unloads our datastore plugin.
185  *
186  * @param api api to unload
187  */
188 static void
189 unload_plugin (struct GNUNET_DATASTORE_PluginFunctions * api,
190                struct GNUNET_CONFIGURATION_Handle *cfg)
191 {
192   char *name;
193   char *libname;
194
195   if (GNUNET_OK !=
196       GNUNET_CONFIGURATION_get_value_string (cfg,
197                                              "DATASTORE", "DATABASE", &name))
198     {
199       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
200                   _("No `%s' specified for `%s' in configuration!\n"),
201                   "DATABASE",
202                   "DATASTORE");
203       return;
204     }
205   GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name);
206   GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api));
207   GNUNET_free (libname);
208   GNUNET_free (name);
209 }
210
211
212
213 /**
214  * Last task run during shutdown.  Disconnects us from
215  * the transport and core.
216  */
217 static void
218 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
219 {
220   struct CpsRunContext *crc = cls;
221
222   unload_plugin (crc->api, crc->cfg);
223   GNUNET_free (crc);
224 }
225
226
227 static void
228 test (void *cls,
229       const struct GNUNET_SCHEDULER_TaskContext *tc)
230 {  
231   struct CpsRunContext *crc = cls;
232   int j;
233
234   switch (crc->phase)
235     {
236     case RP_PUT:      
237       crc->start = GNUNET_TIME_absolute_get ();
238       for (j=0;j<PUT_10;j++)
239         putValue (crc->api, j, crc->i);
240       crc->end = GNUNET_TIME_absolute_get ();
241       printf ("%3u insertion              took %20llums\n", crc->i,
242               (unsigned long long) (crc->end.value - crc->start.value));
243       crc->i++;
244       crc->phase = RP_LP_GET;
245       GNUNET_SCHEDULER_add_after (crc->sched,
246                                   GNUNET_NO,
247                                   GNUNET_SCHEDULER_PRIORITY_KEEP,
248                                   GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
249                                   &test, crc);
250       break;
251     case RP_LP_GET:
252       crc->start = GNUNET_TIME_absolute_get ();      
253       crc->msg = "%3u low priority iteration took %20llums\n";
254       crc->api->iter_low_priority (crc->api->cls, 0, 
255                                    &iterateDummy,
256                                    crc);
257       break;
258     case RP_AE_GET:
259       crc->start = GNUNET_TIME_absolute_get ();      
260       crc->msg = "%3u ascending expiration iteration took %20llums\n";
261       crc->api->iter_ascending_expiration (crc->api->cls, 0, 
262                                       &iterateDummy,
263                                       crc);
264       break;
265     case RP_ZA_GET:
266       crc->start = GNUNET_TIME_absolute_get ();      
267       crc->msg = "%3u zero anonymity iteration took %20llums\n";
268       crc->api->iter_zero_anonymity (crc->api->cls, 0, 
269                                      &iterateDummy,
270                                      crc);
271       break;
272     case RP_MO_GET:
273       crc->start = GNUNET_TIME_absolute_get ();      
274       crc->msg = "%3u migration order iteration took %20llums\n";
275       crc->api->iter_migration_order (crc->api->cls, 0, 
276                                       &iterateDummy,
277                                       crc);
278       break;
279     case RP_AN_GET:
280       crc->start = GNUNET_TIME_absolute_get ();      
281       crc->msg = "%3u all now iteration took %20llums\n";
282       crc->api->iter_all_now (crc->api->cls, 0,
283                               &iterateDummy,
284                               crc);
285       break;
286     case RP_DONE:
287       crc->api->drop (crc->api->cls);
288       GNUNET_SCHEDULER_add_delayed (crc->sched,
289                                     GNUNET_YES,
290                                     GNUNET_SCHEDULER_PRIORITY_IDLE,
291                                     GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
292                                     GNUNET_TIME_UNIT_ZERO,
293                                     &cleaning_task, crc);
294       break;
295     }
296 }
297
298
299 /**
300  * Load the datastore plugin.
301  */
302 static struct GNUNET_DATASTORE_PluginFunctions *
303 load_plugin (struct GNUNET_CONFIGURATION_Handle *cfg,
304              struct GNUNET_SCHEDULER_Handle *sched)
305 {
306   static struct GNUNET_DATASTORE_PluginEnvironment env;
307   struct GNUNET_DATASTORE_PluginFunctions * ret; 
308   char *name;
309   char *libname;
310
311   if (GNUNET_OK !=
312       GNUNET_CONFIGURATION_get_value_string (cfg,
313                                              "DATASTORE", "DATABASE", &name))
314     {
315       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
316                   _("No `%s' specified for `%s' in configuration!\n"),
317                   "DATABASE",
318                   "DATASTORE");
319       return NULL;
320     }
321   env.cfg = cfg;
322   env.sched = sched;  
323   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
324               _("Loading `%s' datastore plugin\n"), name);
325   GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name);
326   GNUNET_assert (NULL != (ret = GNUNET_PLUGIN_load (libname, &env)));
327   GNUNET_free (libname);
328   GNUNET_free (name);
329   return ret;
330 }
331
332
333 static void
334 run (void *cls,
335      struct GNUNET_SCHEDULER_Handle *s,
336      char *const *args,
337      const char *cfgfile,
338      struct GNUNET_CONFIGURATION_Handle *c)
339 {
340   struct GNUNET_DATASTORE_PluginFunctions *api;
341   struct CpsRunContext *crc;
342
343   api = load_plugin (c, s);
344   GNUNET_assert (api != NULL);
345   crc = GNUNET_malloc(sizeof(struct CpsRunContext));
346   crc->api = api;
347   crc->sched = s;
348   crc->cfg = c;
349   crc->phase = RP_PUT;
350   GNUNET_SCHEDULER_add_after (s,
351                               GNUNET_YES,
352                               GNUNET_SCHEDULER_PRIORITY_KEEP,
353                               GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
354                               &test, crc);
355 }
356
357
358 static int
359 check ()
360 {
361   char *const argv[] = { 
362     "perf-plugin-datastore",
363     "-c",
364     "perf_plugin_datastore_data.conf",
365 #if VERBOSE
366     "-L", "DEBUG",
367 #endif
368     NULL
369   };
370   struct GNUNET_GETOPT_CommandLineOption options[] = {
371     GNUNET_GETOPT_OPTION_END
372   };
373   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
374                       argv, "perf-plugin-datastore", "nohelp",
375                       options, &run, NULL);
376   if (ok != 0)
377     fprintf (stderr, "Missed some testcases: %u\n", ok);
378   return ok;
379 }
380
381
382 int
383 main (int argc, char *argv[])
384 {
385   int ret;
386
387   GNUNET_log_setup ("perf-plugin-datastore",
388 #if VERBOSE
389                     "DEBUG",
390 #else
391                     "WARNING",
392 #endif
393                     NULL);
394   ret = check ();
395
396   return ret;
397 }
398
399
400 /* end of perf_plugin_datastore.c */
401
402