f04981135580e5243c29130f93706bc4cd069569
[vlc.git] / modules / misc / testsuite / test4.c
1 /*****************************************************************************
2  * test4.c : Miscellaneous stress tests module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: test4.c,v 1.4 2002/11/10 18:04:22 sam Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <vlc/vlc.h>
28
29 #include <stdlib.h>
30 #include <signal.h>
31
32 /*****************************************************************************
33  * Defines
34  *****************************************************************************/
35 #define MAXVAR        50                    /* Number of variables to create */
36 #define MAXSET      2000                       /* Number of variables to set */
37 #define MAXOBJ      1000                      /* Number of objects to create */
38 #define MAXLOOK    10000                      /* Number of objects to lookup */
39 #define MAXTH          4                       /* Number of threads to spawn */
40
41 /*****************************************************************************
42  * Local prototypes.
43  *****************************************************************************/
44 static int    Foo       ( vlc_object_t *, char *, char * );
45
46 static int    Callback  ( vlc_object_t *, char *, char * );
47 static int    MyCallback( vlc_object_t *, char const *,
48                           vlc_value_t, vlc_value_t, void * );
49 static void * MyThread  ( vlc_object_t * );
50
51 static int    Stress    ( vlc_object_t *, char *, char * );
52 static void * Dummy     ( vlc_object_t * );
53
54 static int    Signal    ( vlc_object_t *, char *, char * );
55
56 /*****************************************************************************
57  * Module descriptor.
58  *****************************************************************************/
59 vlc_module_begin();
60     set_description( _("Miscellaneous stress tests") );
61     var_Create( p_module->p_libvlc, "foo-test", VLC_VAR_COMMAND );
62     var_Set( p_module->p_libvlc, "foo-test", (vlc_value_t)(void*)Foo );
63     var_Create( p_module->p_libvlc, "callback-test", VLC_VAR_COMMAND );
64     var_Set( p_module->p_libvlc, "callback-test", (vlc_value_t)(void*)Callback );
65     var_Create( p_module->p_libvlc, "stress-test", VLC_VAR_COMMAND );
66     var_Set( p_module->p_libvlc, "stress-test", (vlc_value_t)(void*)Stress );
67     var_Create( p_module->p_libvlc, "signal", VLC_VAR_COMMAND );
68     var_Set( p_module->p_libvlc, "signal", (vlc_value_t)(void*)Signal );
69 vlc_module_end();
70
71 /*****************************************************************************
72  * Foo: put anything here
73  *****************************************************************************/
74 static int Foo( vlc_object_t *p_this, char *psz_cmd, char *psz_arg )
75 {
76     vlc_value_t val;
77     int i, i_vals;
78     vlc_value_t *p_vals;
79
80     var_Create( p_this, "honk", VLC_VAR_STRING | VLC_VAR_ISLIST );
81
82     val.psz_string = "foo";
83     var_Change( p_this, "honk", VLC_VAR_ADDCHOICE, &val );
84     val.psz_string = "bar";
85     var_Change( p_this, "honk", VLC_VAR_ADDCHOICE, &val );
86     val.psz_string = "baz";
87     var_Change( p_this, "honk", VLC_VAR_ADDCHOICE, &val );
88     var_Change( p_this, "honk", VLC_VAR_SETDEFAULT, &val );
89
90     var_Get( p_this, "honk", &val ); printf( "value: %s\n", val.psz_string );
91
92     val.psz_string = "foo";
93     var_Set( p_this, "honk", val );
94
95     var_Get( p_this, "honk", &val ); printf( "value: %s\n", val.psz_string );
96
97     val.psz_string = "blork";
98     var_Set( p_this, "honk", val );
99
100     var_Get( p_this, "honk", &val ); printf( "value: %s\n", val.psz_string );
101
102     val.psz_string = "baz";
103     var_Change( p_this, "honk", VLC_VAR_DELCHOICE, &val );
104
105     var_Get( p_this, "honk", &val ); printf( "value: %s\n", val.psz_string );
106
107     var_Change( p_this, "honk", VLC_VAR_GETLIST, &val );
108     i_vals = ((vlc_value_t*)val.p_address)[0].i_int;
109     p_vals = &((vlc_value_t*)val.p_address)[1];
110     for( i = 0 ; i < i_vals ; i++ )
111     {
112         printf( "value %i: %s\n", i, p_vals[i].psz_string );
113     }
114     var_Change( p_this, "honk", VLC_VAR_FREELIST, &val );
115
116     var_Destroy( p_this, "honk" );
117
118     return VLC_SUCCESS;
119 }
120
121 /*****************************************************************************
122  * Callback: test callback functions
123  *****************************************************************************/
124 static int Callback( vlc_object_t *p_this, char *psz_cmd, char *psz_arg )
125 {
126     int i;
127     char psz_var[20];
128     vlc_object_t *pp_objects[10];
129     vlc_value_t val;
130
131     /* Allocate a few variables */
132     for( i = 0; i < 1000; i++ )
133     {
134         sprintf( psz_var, "blork-%i", i );
135         var_Create( p_this, psz_var, VLC_VAR_INTEGER );
136         var_AddCallback( p_this, psz_var, MyCallback, NULL );
137     }
138
139     /*
140      *  Test #1: callback loop detection
141      */
142     printf( "Test #1: callback loop detection\n" );
143
144     printf( " - without boundary check (vlc should print an error)\n" );
145     val.i_int = 1234567;
146     var_Set( p_this, "blork-12", val );
147
148     printf( " - with boundary check\n" );
149     val.i_int = 12;
150     var_Set( p_this, "blork-12", val );
151
152     /*
153      *  Test #2: concurrent access
154      */
155     printf( "Test #2: concurrent access\n" );
156
157     printf( " - launch worker threads\n" );
158
159     for( i = 0; i < 10; i++ )
160     {
161         pp_objects[i] = vlc_object_create( p_this, VLC_OBJECT_GENERIC );
162         vlc_object_attach( pp_objects[i], p_this );
163         vlc_thread_create( pp_objects[i], "foo", MyThread, 0, VLC_TRUE );
164     }
165
166     msleep( 3000000 );
167
168     printf( " - kill worker threads\n" );
169
170     for( i = 0; i < 10; i++ )
171     {
172         pp_objects[i]->b_die = VLC_TRUE;
173         vlc_thread_join( pp_objects[i] );
174         vlc_object_detach( pp_objects[i] );
175         vlc_object_destroy( pp_objects[i] );
176     }
177
178     /* Clean our mess */
179     for( i = 0; i < 1000; i++ )
180     {
181         sprintf( psz_var, "blork-%i", i );
182         var_DelCallback( p_this, psz_var, MyCallback, NULL );
183         var_Destroy( p_this, psz_var );
184     }
185
186     return VLC_SUCCESS;
187 }
188
189 /*****************************************************************************
190  * MyCallback: used by callback-test
191  *****************************************************************************/
192 static int MyCallback( vlc_object_t *p_this, char const *psz_var,
193                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
194 {
195     int i_var = 1 + atoi( psz_var + strlen("blork-") );
196     char psz_newvar[20];
197
198     if( i_var == 1000 )
199     {
200         i_var = 0;
201     }
202
203     /* If we are requested to stop, then stop. */
204     if( i_var == newval.i_int )
205     {
206         return VLC_SUCCESS;
207     }
208
209     /* If we're the blork-3 callback, set blork-4, and so on. */
210     sprintf( psz_newvar, "blork-%i", i_var );
211     var_Set( p_this, psz_newvar, newval );
212
213     return VLC_SUCCESS;   
214 }
215
216 /*****************************************************************************
217  * MyThread: used by callback-test, creates objects and then do nothing.
218  *****************************************************************************/
219 static void * MyThread( vlc_object_t *p_this )
220 {
221     char psz_var[20];
222     vlc_value_t val;
223     vlc_object_t *p_parent = p_this->p_parent;
224
225     vlc_thread_ready( p_this );
226
227     val.i_int = 42;
228
229     while( !p_this->b_die )
230     {
231         int i = (int) (100.0 * rand() / (RAND_MAX));
232
233         sprintf( psz_var, "blork-%i", i );
234         val.i_int = i + 200;
235         var_Set( p_parent, psz_var, val );
236
237         /* This is quite heavy, but we only have 10 threads. Keep cool. */
238         msleep( 1000 );
239     }
240
241     return NULL;
242 }
243
244 /*****************************************************************************
245  * Stress: perform various stress tests
246  *****************************************************************************/
247 static int Stress( vlc_object_t *p_this, char *psz_cmd, char *psz_arg )
248 {
249     vlc_object_t **pp_objects;
250     mtime_t start;
251     char ** ppsz_name;
252     char *  psz_blob;
253     int     i, i_level;
254
255     if( *psz_arg )
256     {
257         i_level = atoi( psz_arg );
258         if( i_level <= 0 )
259         {
260             i_level = 1;
261         }
262         else if( i_level > 200 )
263         {
264             /* It becomes quite dangerous above 150 */
265             i_level = 200;
266         }
267     }
268     else
269     {
270         i_level = 10;
271     }
272
273     /* Allocate required data */
274     ppsz_name = malloc( MAXVAR * i_level * sizeof(char*) );
275     psz_blob = malloc( 20 * MAXVAR * i_level * sizeof(char) );
276     for( i = 0; i < MAXVAR * i_level; i++ )
277     {
278         ppsz_name[i] = psz_blob + 20 * i;
279     }
280
281     pp_objects = malloc( MAXOBJ * i_level * sizeof(void*) );
282
283     /*
284      *  Test #1: objects
285      */
286     printf( "Test #1: objects\n" );
287
288     printf( " - creating %i objects\n", MAXOBJ * i_level );
289     start = mdate();
290     for( i = 0; i < MAXOBJ * i_level; i++ )
291     {
292         pp_objects[i] = vlc_object_create( p_this, VLC_OBJECT_GENERIC );
293     }
294
295     printf( " - randomly looking up %i objects\n", MAXLOOK * i_level );
296     for( i = MAXLOOK * i_level; i--; )
297     {
298         int id = (int) (MAXOBJ * i_level * 1.0 * rand() / (RAND_MAX));
299         vlc_object_get( p_this, pp_objects[id]->i_object_id );
300     }
301
302     printf( " - destroying the objects (LIFO)\n" );
303     for( i = MAXOBJ * i_level; i--; )
304     {
305         vlc_object_destroy( pp_objects[i] );
306     }
307
308     printf( "done (%fs).\n", (mdate() - start) / 1000000.0 );
309
310     /*
311      *  Test #2: integer variables
312      */
313     printf( "Test #2: integer variables\n" );
314
315     printf( " - creating %i integer variables\n", MAXVAR * i_level );
316     start = mdate();
317     for( i = 0; i < MAXVAR * i_level; i++ )
318     {
319         sprintf( ppsz_name[i], "foo-%04i-bar-%04x", i, i * 11 );
320         var_Create( p_this, ppsz_name[i], VLC_VAR_INTEGER );
321     }
322
323     printf( " - randomly assigning %i values\n", MAXSET * i_level );
324     for( i = 0; i < MAXSET * i_level; i++ )
325     {
326         int v = (int) (MAXVAR * i_level * 1.0 * rand() / (RAND_MAX));
327         var_Set( p_this, ppsz_name[v], (vlc_value_t)i );
328     }
329
330     printf( " - destroying the variables\n" );
331     for( i = 0; i < MAXVAR * i_level; i++ )
332     {
333         var_Destroy( p_this, ppsz_name[i] );
334     }
335
336     printf( "done (%fs).\n", (mdate() - start) / 1000000.0 );
337
338     /*
339      *  Test #3: string variables
340      */
341     printf( "Test #3: string variables\n" );
342
343     printf( " - creating %i string variables\n", MAXVAR * i_level );
344     start = mdate();
345     for( i = 0; i < MAXVAR * i_level; i++ )
346     {
347         sprintf( ppsz_name[i], "foo-%04i-bar-%04x", i, i * 11 );
348         var_Create( p_this, ppsz_name[i], VLC_VAR_STRING );
349     }
350
351     printf( " - randomly assigning %i values\n", MAXSET * i_level );
352     for( i = 0; i < MAXSET * i_level; i++ )
353     {
354         int v = (int) (MAXVAR * i_level * 1.0 * rand() / (RAND_MAX));
355         var_Set( p_this, ppsz_name[v], (vlc_value_t)ppsz_name[v] );
356     }
357
358     printf( " - destroying the variables\n" );
359     for( i = 0; i < MAXVAR * i_level; i++ )
360     {
361         var_Destroy( p_this, ppsz_name[i] );
362     }
363
364     printf( "done (%fs).\n", (mdate() - start) / 1000000.0 );
365
366     /*
367      *  Test #4: threads
368      */
369     printf( "Test #4: threads\n" );
370     start = mdate();
371
372     printf( " - spawning %i threads that will each create %i objects\n",
373             MAXTH * i_level, MAXOBJ/MAXTH );
374     for( i = 0; i < MAXTH * i_level; i++ )
375     {
376         pp_objects[i] = vlc_object_create( p_this, VLC_OBJECT_GENERIC );
377         vlc_thread_create( pp_objects[i], "foo", Dummy, 0, VLC_TRUE );
378     }
379
380     printf( " - killing the threads (LIFO)\n" );
381     for( i = MAXTH * i_level; i--; )
382     {
383         pp_objects[i]->b_die = VLC_TRUE;
384         vlc_thread_join( pp_objects[i] );
385         vlc_object_destroy( pp_objects[i] );
386     }
387
388     printf( "done (%fs).\n", (mdate() - start) / 1000000.0 );
389
390     /* Free required data */
391     free( pp_objects );
392     free( psz_blob );
393     free( ppsz_name );
394
395     return VLC_SUCCESS;
396 }
397
398 /*****************************************************************************
399  * Dummy: used by stress-test, creates objects and then do nothing.
400  *****************************************************************************/
401 static void * Dummy( vlc_object_t *p_this )
402 {
403     int i;
404     vlc_object_t *pp_objects[MAXOBJ/MAXTH];
405
406     for( i = 0; i < MAXOBJ/MAXTH; i++ )
407     {
408         pp_objects[i] = vlc_object_create( p_this, VLC_OBJECT_GENERIC );
409     }
410
411     vlc_thread_ready( p_this );
412
413     while( !p_this->b_die )
414     {
415         msleep( 10000 );
416     }
417
418     for( i = MAXOBJ/MAXTH; i--; )
419     {
420         vlc_object_destroy( pp_objects[i] );
421     }
422
423     return NULL;
424 }
425
426 /*****************************************************************************
427  * Signal: send a signal to the current thread.
428  *****************************************************************************/
429 static int Signal( vlc_object_t *p_this, char *psz_cmd, char *psz_arg )
430 {
431     raise( atoi(psz_arg) );
432     return VLC_SUCCESS;
433 }
434