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