From 8d995e6f088eeee7d5ee5896b23c0a1347b27256 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Cl=C3=A9ment=20Stenac?= Date: Fri, 3 Feb 2006 23:52:45 +0000 Subject: [PATCH] Use a hash for stats. Not finished --- Makefile.am | 1 + include/vlc_common.h | 15 +++ include/vlc_messages.h | 4 +- include/vlc_symbols.h | 12 +++ src/misc/hashtables.c | 223 +++++++++++++++++++++++++++++++++++++++++ src/misc/stats.c | 31 +++--- 6 files changed, 265 insertions(+), 21 deletions(-) create mode 100644 src/misc/hashtables.c diff --git a/Makefile.am b/Makefile.am index 0c36d11056..139dba4f9c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -470,6 +470,7 @@ SOURCES_libvlc_common = \ src/misc/update.c \ src/misc/vlm.c \ src/misc/xml.c \ + src/misc/hashtables.c \ src/misc/version.c \ src/extras/libc.c \ src/control/core.c \ diff --git a/include/vlc_common.h b/include/vlc_common.h index 3f16671f93..7daebe4ae7 100644 --- a/include/vlc_common.h +++ b/include/vlc_common.h @@ -202,6 +202,7 @@ typedef struct libvlc_t libvlc_t; typedef struct vlc_t vlc_t; typedef struct variable_t variable_t; typedef struct date_t date_t; +typedef struct hashtable_entry_t hashtable_entry_t; /* Messages */ typedef struct msg_bank_t msg_bank_t; @@ -642,6 +643,20 @@ static int64_t GCD( int64_t a, int64_t b ) } \ } +/* Hash tables handling */ +struct hashtable_entry_t +{ + int i_id; + char *psz_name; + uint64_t i_hash; + void *p_data; +}; + +VLC_EXPORT( void, vlc_HashInsert, (hashtable_entry_t **, int *, int, const char *, void *)); +VLC_EXPORT( void*, vlc_HashRetrieve, (hashtable_entry_t*, int, int, const char *) ); +VLC_EXPORT( int, vlc_HashLookup, (hashtable_entry_t *, int, int, const char *) ); + + /* MSB (big endian)/LSB (little endian) conversions - network order is always * MSB, and should be used for both network communications and files. Note that * byte orders other than little and big endians are not supported, but only diff --git a/include/vlc_messages.h b/include/vlc_messages.h index 6b0343e123..b1f2fbd694 100644 --- a/include/vlc_messages.h +++ b/include/vlc_messages.h @@ -243,8 +243,8 @@ struct stats_handler_t { VLC_COMMON_MEMBERS - int i_counters; - counter_t **pp_counters; + int i_counters; + hashtable_entry_t * p_counters; }; VLC_EXPORT( void, stats_HandlerDestroy, (stats_handler_t*) ); diff --git a/include/vlc_symbols.h b/include/vlc_symbols.h index 190850f47e..e22d64f162 100644 --- a/include/vlc_symbols.h +++ b/include/vlc_symbols.h @@ -308,6 +308,7 @@ int playlist_ItemAdd (playlist_t *, playlist_item_t *, int, int); aout_buffer_t * aout_OutputNextBuffer (aout_instance_t *, mtime_t, vlc_bool_t); int playlist_LockReplace (playlist_t *,playlist_item_t *, input_item_t*); int __intf_Eject (vlc_object_t *, const char *); +void vlc_HashInsert (hashtable_entry_t **, int *, int, const char *, void *); int input_Control (input_thread_t *, int i_query, ...); int __aout_VolumeUp (vlc_object_t *, int, audio_volume_t *); void osd_Message (spu_t *, int, char *, ...); @@ -316,6 +317,7 @@ void __osd_MenuUp (vlc_object_t *); int __aout_VolumeDown (vlc_object_t *, int, audio_volume_t *); sout_instance_t * __sout_NewInstance (vlc_object_t *, char *); subpicture_t * spu_CreateSubpicture (spu_t *); +int vlc_HashLookup (hashtable_entry_t *, int, int, const char *); void httpd_MsgAdd (httpd_message_t *, char *psz_name, char *psz_value, ...); int vout_vaControlDefault (vout_thread_t *, int, va_list); int playlist_NodeEmpty (playlist_t *, playlist_item_t *, vlc_bool_t); @@ -359,6 +361,7 @@ int intf_RunThread (intf_thread_t *); int httpd_StreamSend (httpd_stream_t *, uint8_t *p_data, int i_data); decoder_t * input_DecoderNew (input_thread_t *, es_format_t *, vlc_bool_t b_force_decoder); xml_t * __xml_Create (vlc_object_t *); +void* vlc_HashRetrieve (hashtable_entry_t*, int, int, const char *); msg_subscription_t* __msg_Subscribe (vlc_object_t *, int); const char * VLC_Version (void); session_descriptor_t* sout_AnnounceRegisterSDP (sout_instance_t *,const char *, const char *, announce_method_t*); @@ -919,6 +922,9 @@ struct module_symbols_t unsigned int (*update_iterator_ChooseMirrorAndFile_inner) (update_iterator_t *, int, int, int); update_t * (*__update_New_inner) (vlc_object_t *); void (*update_download_inner) (update_iterator_t *, char *); + void (*vlc_HashInsert_inner) (hashtable_entry_t **, int *, int, const char *, void *); + int (*vlc_HashLookup_inner) (hashtable_entry_t *, int, int, const char *); + void* (*vlc_HashRetrieve_inner) (hashtable_entry_t*, int, int, const char *); }; # if defined (__PLUGIN__) # define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner @@ -1363,6 +1369,9 @@ struct module_symbols_t # define update_iterator_ChooseMirrorAndFile (p_symbols)->update_iterator_ChooseMirrorAndFile_inner # define __update_New (p_symbols)->__update_New_inner # define update_download (p_symbols)->update_download_inner +# define vlc_HashInsert (p_symbols)->vlc_HashInsert_inner +# define vlc_HashLookup (p_symbols)->vlc_HashLookup_inner +# define vlc_HashRetrieve (p_symbols)->vlc_HashRetrieve_inner # elif defined (HAVE_DYNAMIC_PLUGINS) && !defined (__BUILTIN__) /****************************************************************** * STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access. @@ -1810,6 +1819,9 @@ struct module_symbols_t ((p_symbols)->update_iterator_ChooseMirrorAndFile_inner) = update_iterator_ChooseMirrorAndFile; \ ((p_symbols)->__update_New_inner) = __update_New; \ ((p_symbols)->update_download_inner) = update_download; \ + ((p_symbols)->vlc_HashInsert_inner) = vlc_HashInsert; \ + ((p_symbols)->vlc_HashLookup_inner) = vlc_HashLookup; \ + ((p_symbols)->vlc_HashRetrieve_inner) = vlc_HashRetrieve; \ (p_symbols)->net_ConvertIPv4_deprecated = NULL; \ (p_symbols)->__stats_CounterGet_deprecated = NULL; \ (p_symbols)->__stats_TimerDumpAll_deprecated = NULL; \ diff --git a/src/misc/hashtables.c b/src/misc/hashtables.c new file mode 100644 index 0000000000..3e24c9a418 --- /dev/null +++ b/src/misc/hashtables.c @@ -0,0 +1,223 @@ +/***************************************************************************** + * hashtables.c: Hash tables handling + ***************************************************************************** + * Copyright (C) 2002-2004 the VideoLAN team + * $Id: variables.c 13991 2006-01-22 17:12:24Z zorglub $ + * + * Authors: Samuel Hocevar + * Clément Stenac + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include + +static uint64_t HashString ( const char *, int ); +static int FindSlot ( hashtable_entry_t *, int, uint64_t ); +static int LookupInner ( hashtable_entry_t *, int, uint64_t ); + + + +void vlc_HashInsert( hashtable_entry_t **pp_array, int *pi_count, int i_id, + const char *psz_name, void *p_data ) +{ + hashtable_entry_t *p_new; + int64_t i_hash = HashString( psz_name, i_id ); + int i_new = FindSlot( *pp_array, *pi_count, i_hash ); + + *pp_array = realloc( *pp_array, ( *pi_count + 2) * sizeof( hashtable_entry_t ) ); + + memmove( *pp_array + i_new + 1 , *pp_array + i_new, ( *pi_count - i_new ) * + sizeof( hashtable_entry_t ) ); + (*pi_count)++; + + p_new = &((*pp_array)[i_new]); + p_new->i_hash = i_hash; + p_new->i_id = i_id; + p_new->psz_name = strdup( psz_name ); + p_new->p_data = p_data; + +} + +void * vlc_HashRetrieve( hashtable_entry_t *p_array, int i_count, int i_id, + const char *psz_name ) +{ + int i_new = vlc_HashLookup( p_array, i_count, i_id, psz_name ); + + if( i_new >= 0 && i_new < i_count ) + { + return p_array[i_new].p_data; + } + return NULL; +} + +/***************************************************************************** + * FindSlot: find an empty slot to insert a new variable + ***************************************************************************** + * We use a recursive inner function indexed on the hash. This function does + * nothing in the rare cases where a collision may occur, see Lookup() + * to see how we handle them. + * XXX: does this really need to be written recursively? + *****************************************************************************/ +static int FindSlot( hashtable_entry_t *p_array, int i_count, uint64_t i_hash ) +{ + int i_middle; + + + if( i_hash <= p_array[0].i_hash ) + { + return 0; + } + + if( i_hash >= p_array[i_count - 1].i_hash ) + { + return i_count; + } + + i_middle = i_count / 2; + + /* We know that 0 < i_middle */ + if( i_hash < p_array[i_middle].i_hash ) + { + return FindSlot( p_array, i_middle, i_hash ); + } + + /* We know that i_middle + 1 < i_count */ + if( i_hash > p_array[i_middle + 1].i_hash ) + { + return i_middle + 1 + FindSlot( p_array + i_middle + 1, + i_count - i_middle - 1, + i_hash ); + } + + return i_middle + 1; +} + +/***************************************************************************** + * Lookup: find an existing variable given its name and id + ***************************************************************************** + * We use a recursive inner function indexed on the hash. Care is taken of + * possible hash collisions. + * XXX: does this really need to be written recursively? + *****************************************************************************/ +int vlc_HashLookup( hashtable_entry_t *p_array, int i_count, + int i_id, const char *psz_name ) +{ + uint64_t i_hash; + int i, i_pos; + + if( i_count == 0 ) + { + return -1; + } + + i_hash = HashString( psz_name, i_id ); + + i_pos = LookupInner( p_array, i_count, i_hash ); + + /* Hash not found */ + if( i_hash != p_array[i_pos].i_hash ) + { + return -1; + } + + /* Hash found, entry found */ + if( !strcmp( psz_name, p_array[i_pos].psz_name ) ) + { + return i_pos; + } + + /* Hash collision! This should be very rare, but we cannot guarantee + * it will never happen. Just do an exhaustive search amongst all + * entries with the same hash. */ + for( i = i_pos - 1 ; i > 0 && i_hash == p_array[i].i_hash ; i-- ) + { + if( !strcmp( psz_name, p_array[i].psz_name ) && p_array[i].i_id == i_id ) + { + return i; + } + } + + for( i = i_pos + 1 ; i < i_count && i_hash == p_array[i].i_hash ; i++ ) + { + if( !strcmp( psz_name, p_array[i].psz_name ) && p_array[i].i_id == i_id ) + { + return i; + } + } + + /* Hash found, but entry not found */ + return -1; +} + +static int LookupInner( hashtable_entry_t *p_array, int i_count, uint64_t i_hash ) +{ + int i_middle; + + if( i_hash <= p_array[0].i_hash ) + { + return 0; + } + + if( i_hash >= p_array[i_count-1].i_hash ) + { + return i_count - 1; + } + + i_middle = i_count / 2; + + /* We know that 0 < i_middle */ + if( i_hash < p_array[i_middle].i_hash ) + { + return LookupInner( p_array, i_middle, i_hash ); + } + + /* We know that i_middle + 1 < i_count */ + if( i_hash > p_array[i_middle].i_hash ) + { + return i_middle + LookupInner( p_array + i_middle, + i_count - i_middle, + i_hash ); + } + + return i_middle; +} + + +/***************************************************************************** + * HashString: our cool hash function + ***************************************************************************** + * This function is not intended to be crypto-secure, we only want it to be + * fast and not suck too much. This one is pretty fast and did 0 collisions + * in wenglish's dictionary. + *****************************************************************************/ +static uint64_t HashString( const char *psz_string, int i_id ) +{ + uint64_t i_hash = 0; + + while( *psz_string ) + { + i_hash += *psz_string++; + i_hash += i_hash << 10; + i_hash ^= i_hash >> 8; + } + + i_hash += ( i_id << 32 ); + + return i_hash; +} diff --git a/src/misc/stats.c b/src/misc/stats.c index 8d919e40cc..fe04bb154d 100644 --- a/src/misc/stats.c +++ b/src/misc/stats.c @@ -57,7 +57,8 @@ void stats_HandlerDestroy( stats_handler_t *p_stats ) for ( i = p_stats->i_counters - 1 ; i >= 0 ; i-- ) { int j; - counter_t * p_counter = p_stats->pp_counters[i]; + hashtable_entry_t p_entry = p_stats->p_counters[i]; + counter_t * p_counter = p_entry.p_data; for( j = p_counter->i_samples -1; j >= 0 ; j-- ) { @@ -66,7 +67,8 @@ void stats_HandlerDestroy( stats_handler_t *p_stats ) free( p_sample ); } free( p_counter->psz_name ); - REMOVE_ELEM( p_stats->pp_counters, p_stats->i_counters, i ); + free( p_entry.psz_name ); + REMOVE_ELEM( p_stats->p_counters, p_stats->i_counters, i ); free( p_counter ); } } @@ -109,10 +111,8 @@ int __stats_Create( vlc_object_t *p_this, const char *psz_name, int i_type, p_counter->update_interval = 0; p_counter->last_update = 0; - INSERT_ELEM( p_handler->pp_counters, - p_handler->i_counters, - p_handler->i_counters, - p_counter ); + vlc_HashInsert( &p_handler->p_counters, &p_handler->i_counters, p_this->i_object_id, + psz_name, p_counter ); vlc_mutex_unlock( &p_handler->object_lock ); @@ -467,9 +467,10 @@ void __stats_TimersDumpAll( vlc_object_t *p_obj ) vlc_mutex_lock( &p_handler->object_lock ); for ( i = 0 ; i< p_handler->i_counters; i++ ) { - if( p_handler->pp_counters[i]->i_compute_type == STATS_TIMER ) + counter_t * p_counter = (counter_t *)(p_handler->p_counters[i].p_data); + if( p_counter->i_compute_type == STATS_TIMER ) { - TimerDump( p_obj, p_handler->pp_counters[i], VLC_FALSE ); + TimerDump( p_obj, p_counter, VLC_FALSE ); } } vlc_mutex_unlock( &p_handler->object_lock ); @@ -613,16 +614,8 @@ static counter_t *GetCounter( stats_handler_t *p_handler, int i_object_id, const char *psz_name ) { int i; - for( i = 0; i< p_handler->i_counters; i++ ) - { - counter_t *p_counter = p_handler->pp_counters[i]; - if( p_counter->i_source_object == i_object_id && - !strcmp( p_counter->psz_name, psz_name ) ) - { - return p_counter; - } - } - return NULL; + return (counter_t *)vlc_HashRetrieve( p_handler->p_counters, p_handler->i_counters, + i_object_id, psz_name ); } @@ -664,7 +657,7 @@ static stats_handler_t* stats_HandlerCreate( vlc_object_t *p_this ) return NULL; } p_handler->i_counters = 0; - p_handler->pp_counters = NULL; + p_handler->p_counters = (hashtable_entry_t *) malloc( 5 * sizeof( variable_t ) ); /// \bug is it p_vlc or p_libvlc ? vlc_object_attach( p_handler, p_this->p_vlc ); -- 2.39.5