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