debugstuff
[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 / 4
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   unsigned int cnt;
80 };
81
82
83              
84 static void
85 putValue (struct GNUNET_DATASTORE_PluginFunctions * api, int i, int k)
86 {
87   char value[65536];
88   size_t size;
89   static GNUNET_HashCode key;
90   static int ic;
91   char *msg;
92   unsigned int prio;
93
94   /* most content is 32k */
95   size = 32 * 1024;
96
97   if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16) == 0)  /* but some of it is less! */
98     size = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024);
99   size = size - (size & 7);     /* always multiple of 8 */
100
101   /* generate random key */
102   key.bits[0] = (unsigned int) GNUNET_TIME_absolute_get ().value;
103   GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &key);
104   memset (value, i, size);
105   if (i > 255)
106     memset (value, i - 255, size / 2);
107   value[0] = k;
108   msg = NULL;
109   prio = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
110   if (GNUNET_OK != api->put (api->cls,
111                              &key, 
112                              size,
113                              value,
114                              i,
115                              prio,
116                              i,
117                              GNUNET_TIME_relative_to_absolute 
118                              (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
119                                                              60 * 60 * 60 * 1000 +
120                                                              GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000))),
121                              &msg))
122     {
123       fprintf (stderr, "ERROR: `%s'\n", msg);
124       GNUNET_free_non_null (msg);
125       return;
126     }
127   ic++;
128   stored_bytes += size;
129   stored_ops++;
130   stored_entries++;
131 }
132
133 static void
134 test (void *cls,
135       const struct GNUNET_SCHEDULER_TaskContext *tc);
136
137
138 static int
139 iterateDummy (void *cls,
140               void *next_cls,
141               const GNUNET_HashCode * key,
142               uint32_t size,
143               const void *data,
144               uint32_t type,
145               uint32_t priority,
146               uint32_t anonymity,
147               struct GNUNET_TIME_Absolute
148               expiration, 
149               uint64_t uid)
150 {
151   struct CpsRunContext *crc = cls;
152   
153   if (key == NULL)
154     {
155       crc->end = GNUNET_TIME_absolute_get();
156       printf (crc->msg,
157               crc->i,
158               (unsigned long long) (crc->end.value - crc->start.value),
159               crc->cnt);
160       if (crc->phase != RP_AN_GET)
161         {
162           crc->phase++;
163         }
164       else
165         {
166           if (crc->i == ITERATIONS)
167             crc->phase = RP_DONE;
168           else
169             crc->phase = RP_PUT;
170         }
171       GNUNET_SCHEDULER_add_after (crc->sched,
172                                   GNUNET_NO,
173                                   GNUNET_SCHEDULER_PRIORITY_KEEP,
174                                   GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
175                                   &test, crc);
176       return GNUNET_OK;
177     }
178 #if VERBOSE
179   fprintf (stderr, "Found result type=%u, priority=%u, size=%u, expire=%llu\n",
180            type, priority, size,
181            (unsigned long long) expiration.value);
182 #endif
183   crc->cnt++;
184   crc->api->next_request (next_cls,
185                           GNUNET_NO);
186   return GNUNET_OK;
187 }
188
189
190
191 /**
192  * Function called when the service shuts
193  * down.  Unloads our datastore plugin.
194  *
195  * @param api api to unload
196  */
197 static void
198 unload_plugin (struct GNUNET_DATASTORE_PluginFunctions * api,
199                struct GNUNET_CONFIGURATION_Handle *cfg)
200 {
201   char *name;
202   char *libname;
203
204   if (GNUNET_OK !=
205       GNUNET_CONFIGURATION_get_value_string (cfg,
206                                              "DATASTORE", "DATABASE", &name))
207     {
208       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
209                   _("No `%s' specified for `%s' in configuration!\n"),
210                   "DATABASE",
211                   "DATASTORE");
212       return;
213     }
214   GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name);
215   GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api));
216   GNUNET_free (libname);
217   GNUNET_free (name);
218 }
219
220
221
222 /**
223  * Last task run during shutdown.  Disconnects us from
224  * the transport and core.
225  */
226 static void
227 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
228 {
229   struct CpsRunContext *crc = cls;
230
231   unload_plugin (crc->api, crc->cfg);
232   GNUNET_free (crc);
233 }
234
235
236 static void
237 test (void *cls,
238       const struct GNUNET_SCHEDULER_TaskContext *tc)
239 {  
240   struct CpsRunContext *crc = cls;
241   int j;
242
243   switch (crc->phase)
244     {
245     case RP_PUT:      
246       crc->start = GNUNET_TIME_absolute_get ();
247       for (j=0;j<PUT_10;j++)
248         putValue (crc->api, j, crc->i);
249       crc->end = GNUNET_TIME_absolute_get ();
250       printf ("%3u insertion took                      %20llums for %u\n",
251               crc->i,
252               (unsigned long long) (crc->end.value - crc->start.value),
253               (unsigned int) PUT_10);
254       crc->i++;
255       crc->phase = RP_LP_GET;
256       GNUNET_SCHEDULER_add_after (crc->sched,
257                                   GNUNET_NO,
258                                   GNUNET_SCHEDULER_PRIORITY_KEEP,
259                                   GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
260                                   &test, crc);
261       break;
262     case RP_LP_GET:
263       crc->cnt = 0;
264       crc->start = GNUNET_TIME_absolute_get ();      
265       crc->msg = "%3u low priority iteration took         %20llums for %u\n";
266       crc->api->iter_low_priority (crc->api->cls, 0, 
267                                    &iterateDummy,
268                                    crc);
269       break;
270     case RP_AE_GET:
271       crc->cnt = 0;
272       crc->start = GNUNET_TIME_absolute_get ();      
273       crc->msg = "%3u ascending expiration iteration took %20llums for %u\n";
274       crc->api->iter_ascending_expiration (crc->api->cls, 0, 
275                                       &iterateDummy,
276                                       crc);
277       break;
278     case RP_ZA_GET:
279       crc->cnt = 0;
280       crc->start = GNUNET_TIME_absolute_get ();      
281       crc->msg = "%3u zero anonymity iteration took       %20llums for %u\n";
282       crc->api->iter_zero_anonymity (crc->api->cls, 0, 
283                                      &iterateDummy,
284                                      crc);
285       break;
286     case RP_MO_GET:
287       crc->cnt = 0;
288       crc->start = GNUNET_TIME_absolute_get ();      
289       crc->msg = "%3u migration order iteration took      %20llums for %u\n";
290       crc->api->iter_migration_order (crc->api->cls, 0, 
291                                       &iterateDummy,
292                                       crc);
293       break;
294     case RP_AN_GET:
295       crc->cnt = 0;
296       crc->start = GNUNET_TIME_absolute_get ();      
297       crc->msg = "%3u all now iteration took              %20llums for %u\n";
298       crc->api->iter_all_now (crc->api->cls, 0,
299                               &iterateDummy,
300                               crc);
301       break;
302     case RP_DONE:
303       crc->api->drop (crc->api->cls);
304       GNUNET_SCHEDULER_add_delayed (crc->sched,
305                                     GNUNET_YES,
306                                     GNUNET_SCHEDULER_PRIORITY_IDLE,
307                                     GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
308                                     GNUNET_TIME_UNIT_ZERO,
309                                     &cleaning_task, crc);
310       break;
311     }
312 }
313
314
315 /**
316  * Load the datastore plugin.
317  */
318 static struct GNUNET_DATASTORE_PluginFunctions *
319 load_plugin (struct GNUNET_CONFIGURATION_Handle *cfg,
320              struct GNUNET_SCHEDULER_Handle *sched)
321 {
322   static struct GNUNET_DATASTORE_PluginEnvironment env;
323   struct GNUNET_DATASTORE_PluginFunctions * ret; 
324   char *name;
325   char *libname;
326
327   if (GNUNET_OK !=
328       GNUNET_CONFIGURATION_get_value_string (cfg,
329                                              "DATASTORE", "DATABASE", &name))
330     {
331       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
332                   _("No `%s' specified for `%s' in configuration!\n"),
333                   "DATABASE",
334                   "DATASTORE");
335       return NULL;
336     }
337   env.cfg = cfg;
338   env.sched = sched;  
339   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
340               _("Loading `%s' datastore plugin\n"), name);
341   GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name);
342   GNUNET_assert (NULL != (ret = GNUNET_PLUGIN_load (libname, &env)));
343   GNUNET_free (libname);
344   GNUNET_free (name);
345   return ret;
346 }
347
348
349 static void
350 run (void *cls,
351      struct GNUNET_SCHEDULER_Handle *s,
352      char *const *args,
353      const char *cfgfile,
354      struct GNUNET_CONFIGURATION_Handle *c)
355 {
356   struct GNUNET_DATASTORE_PluginFunctions *api;
357   struct CpsRunContext *crc;
358
359   api = load_plugin (c, s);
360   GNUNET_assert (api != NULL);
361   crc = GNUNET_malloc(sizeof(struct CpsRunContext));
362   crc->api = api;
363   crc->sched = s;
364   crc->cfg = c;
365   crc->phase = RP_PUT;
366   GNUNET_SCHEDULER_add_after (s,
367                               GNUNET_YES,
368                               GNUNET_SCHEDULER_PRIORITY_KEEP,
369                               GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
370                               &test, crc);
371 }
372
373
374 static int
375 check ()
376 {
377   char *const argv[] = { 
378     "perf-plugin-datastore",
379     "-c",
380     "perf_plugin_datastore_data.conf",
381 #if VERBOSE
382     "-L", "DEBUG",
383 #endif
384     NULL
385   };
386   struct GNUNET_GETOPT_CommandLineOption options[] = {
387     GNUNET_GETOPT_OPTION_END
388   };
389   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
390                       argv, "perf-plugin-datastore", "nohelp",
391                       options, &run, NULL);
392   if (ok != 0)
393     fprintf (stderr, "Missed some testcases: %u\n", ok);
394   return ok;
395 }
396
397
398 int
399 main (int argc, char *argv[])
400 {
401   int ret;
402
403   GNUNET_log_setup ("perf-plugin-datastore",
404 #if VERBOSE
405                     "DEBUG",
406 #else
407                     "WARNING",
408 #endif
409                     NULL);
410   ret = check ();
411
412   return ret;
413 }
414
415
416 /* end of perf_plugin_datastore.c */
417
418