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