1
0
mirror of https://github.com/Llewellynvdm/conky.git synced 2024-12-25 12:10:03 +00:00

moved hash sizing code into portmon lib, where it belongs

git-svn-id: https://conky.svn.sourceforge.net/svnroot/conky/trunk/conky@393 7f574dfc-610e-0410-a909-a81674777703
This commit is contained in:
Philip Kovacs 2005-11-11 20:46:42 +00:00
parent 5d9022d9df
commit 920eac02b6
6 changed files with 96 additions and 57 deletions

View File

@ -259,8 +259,8 @@ int no_buffers;
static int pad_percents = 0; static int pad_percents = 0;
#ifdef TCP_PORT_MONITOR #ifdef TCP_PORT_MONITOR
static int min_port_monitors = 0; /* config item */ tcp_port_monitor_collection_args_t tcp_port_monitor_collection_args;
static int min_port_monitor_connections = 0; /* config item */ tcp_port_monitor_args_t tcp_port_monitor_args;
#endif #endif
/* Text that is shown */ /* Text that is shown */
@ -1826,18 +1826,8 @@ int a = stippled_borders, b = 1;
/* if the port monitor collection hasn't been created, we must create it */ /* if the port monitor collection hasn't been created, we must create it */
if ( !info.p_tcp_port_monitor_collection ) if ( !info.p_tcp_port_monitor_collection )
{ {
double hash_size, log_base_2; info.p_tcp_port_monitor_collection =
create_tcp_port_monitor_collection( &tcp_port_monitor_collection_args );
/* calculate hash_size from min_port_monitors */
hash_size = (double)min_port_monitors / (double)TCP_MONITOR_HASH_MAX_LOAD_PCT;
/* correct hash_size to nearest power of two */
log_base_2 = log(hash_size) / log(2);
if ( log_base_2 - (int)log_base_2 > 0.001 )
log_base_2 = (double)( (int)log_base_2 + 1 );
hash_size = pow(2,log_base_2);
/*fprintf(stderr,"collection hash size is %d\n",(int)hash_size);*/
info.p_tcp_port_monitor_collection = create_tcp_port_monitor_collection( (int)hash_size );
if ( !info.p_tcp_port_monitor_collection ) if ( !info.p_tcp_port_monitor_collection )
{ {
CRIT_ERR("tcp_portmon: unable to create port monitor collection"); CRIT_ERR("tcp_portmon: unable to create port monitor collection");
@ -1847,19 +1837,8 @@ int a = stippled_borders, b = 1;
/* if a port monitor for this port does not exist, create one and add it to the collection */ /* if a port monitor for this port does not exist, create one and add it to the collection */
if ( find_tcp_port_monitor( info.p_tcp_port_monitor_collection, port_begin, port_end ) == NULL ) if ( find_tcp_port_monitor( info.p_tcp_port_monitor_collection, port_begin, port_end ) == NULL )
{ {
double hash_size, log_base_2;
/* calculate hash_size from min_port_monitor_connections */
hash_size = (double)min_port_monitor_connections / (double)TCP_CONNECTION_HASH_MAX_LOAD_PCT;
/* correct hash_size to nearest power of two */
log_base_2 = log(hash_size) / log(2);
if ( log_base_2 - (int)log_base_2 > 0.001)
log_base_2 = (double)( (int)log_base_2 + 1 );
hash_size = pow(2, log_base_2);
/*fprintf(stderr,"monitor hash size is %d\n",(int)hash_size);*/
tcp_port_monitor_t * p_monitor = tcp_port_monitor_t * p_monitor =
create_tcp_port_monitor( port_begin, port_end, (int)hash_size ); create_tcp_port_monitor( port_begin, port_end, &tcp_port_monitor_args );
if ( !p_monitor ) if ( !p_monitor )
{ {
CRIT_ERR("tcp_portmon: unable to create port monitor"); CRIT_ERR("tcp_portmon: unable to create port monitor");
@ -4507,8 +4486,8 @@ static void set_default_configurations(void)
#endif #endif
#ifdef TCP_PORT_MONITOR #ifdef TCP_PORT_MONITOR
min_port_monitors = MIN_PORT_MONITORS_DEFAULT; tcp_port_monitor_collection_args.min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT; tcp_port_monitor_args.min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
#endif #endif
} }
@ -4919,20 +4898,20 @@ else if (strcasecmp(name, a) == 0 || strcasecmp(name, b) == 0)
CONF("min_port_monitors") CONF("min_port_monitors")
{ {
if ( !value || if ( !value ||
(sscanf(value, "%d", &min_port_monitors) != 1) || (sscanf(value, "%d", &tcp_port_monitor_collection_args.min_port_monitors) != 1) ||
min_port_monitors <= 0 ) tcp_port_monitor_collection_args.min_port_monitors <= 0 )
{ {
min_port_monitors = MIN_PORT_MONITORS_DEFAULT; tcp_port_monitor_collection_args.min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
CONF_ERR; CONF_ERR;
} }
} }
CONF("min_port_monitor_connections") CONF("min_port_monitor_connections")
{ {
if ( !value || if ( !value ||
(sscanf(value, "%d", &min_port_monitor_connections) != 1) (sscanf(value, "%d", &tcp_port_monitor_args.min_port_monitor_connections) != 1)
|| min_port_monitor_connections <= 0 ) || tcp_port_monitor_args.min_port_monitor_connections <= 0 )
{ {
min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT; tcp_port_monitor_args.min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
CONF_ERR; CONF_ERR;
} }
} }

View File

@ -114,7 +114,6 @@ struct mpd_s {
#endif #endif
#ifdef TCP_PORT_MONITOR #ifdef TCP_PORT_MONITOR
#include <math.h>
#include "libtcp-portmon.h" #include "libtcp-portmon.h"
#define MIN_PORT_MONITORS_DEFAULT 16 #define MIN_PORT_MONITORS_DEFAULT 16
#define MIN_PORT_MONITOR_CONNECTIONS_DEFAULT 256 #define MIN_PORT_MONITOR_CONNECTIONS_DEFAULT 256

View File

@ -328,7 +328,7 @@ void maintain_tcp_port_monitor_hash(
#ifdef HASH_DEBUG #ifdef HASH_DEBUG
fprintf(stderr,"--- num vacated is %d, vacated factor is %.3f\n", p_monitor->hash.vacated, vacated_load ); fprintf(stderr,"--- num vacated is %d, vacated factor is %.3f\n", p_monitor->hash.vacated, vacated_load );
#endif #endif
if ( vacated_load <= TCP_CONNECIION_HASH_MAX_VACATED_PCT ) if ( vacated_load <= TCP_CONNECIION_HASH_MAX_VACATED_RATIO )
{ {
/* hash is fine and needs no rebalancing */ /* hash is fine and needs no rebalancing */
return; return;
@ -371,7 +371,7 @@ void rebuild_tcp_port_monitor_peek_table(
return; return;
/* zero out the peek array */ /* zero out the peek array */
memset( p_monitor->p_peek, 0, TCP_CONNECTION_HASH_SIZE * sizeof(tcp_connection_t *) ); memset( p_monitor->p_peek, 0, p_monitor->hash.size * sizeof(tcp_connection_t *) );
for ( p_node=p_monitor->connection_list.p_head; p_node!=NULL; p_node=p_node->p_next, i++ ) for ( p_node=p_monitor->connection_list.p_head; p_node!=NULL; p_node=p_node->p_next, i++ )
{ {
@ -427,7 +427,7 @@ void show_connection_to_tcp_port_monitor(
* connection limit. Future versions should probably allow the client to set the hash size * connection limit. Future versions should probably allow the client to set the hash size
* and load limits and/or provide for automatic resizing of hashes. */ * and load limits and/or provide for automatic resizing of hashes. */
if ( (double)p_monitor->hash.size / (double)p_monitor->hash.positions >= TCP_CONNECTION_HASH_MAX_LOAD_PCT ) if ( (double)p_monitor->hash.size / (double)p_monitor->hash.positions >= TCP_CONNECTION_HASH_MAX_LOAD_RATIO )
{ {
/* hash exceeds our load limit is now "full" */ /* hash exceeds our load limit is now "full" */
return; return;
@ -498,6 +498,37 @@ void for_each_tcp_port_monitor_in_collection(
} }
/* ----------------------------------------------------------------------------------------
* Calculate an efficient hash size based on the desired number of elements and load factor.
* ---------------------------------------------------------------------------------------- */
int calc_efficient_hash_size(
int min_elements,
int max_hash_size,
double max_load_factor
)
{
double min_size, hash_size, log_base_2;
/* the size of the hash will the smallest power of two such that the minimum number
of desired elements does not exceed the maximum load factor. */
min_size = (double)min_elements / max_load_factor; /* starting point */
/* now adjust size up to nearest power of two */
log_base_2 = (double) (int) ( log(min_size) / log(2) ) ; /* lop off fractional portion of log */
hash_size = pow(2,log_base_2) >= min_size ? min_size : pow(2,(double)++log_base_2);
/* respect the maximum */
hash_size = hash_size <= max_hash_size ? hash_size : max_hash_size;
/*
fprintf(stderr,"hash size is %d, based on %d min_elements and %.02f max load, %d maximum\n",
(int)hash_size, min_elements, max_load_factor, max_hash_size);
*/
return hash_size;
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
* CLIENT INTERFACE * CLIENT INTERFACE
@ -514,7 +545,7 @@ void for_each_tcp_port_monitor_in_collection(
tcp_port_monitor_t * create_tcp_port_monitor( tcp_port_monitor_t * create_tcp_port_monitor(
in_port_t port_range_begin, in_port_t port_range_begin,
in_port_t port_range_end, in_port_t port_range_end,
int hash_size tcp_port_monitor_args_t * p_creation_args
) )
{ {
tcp_port_monitor_t * p_monitor; tcp_port_monitor_t * p_monitor;
@ -526,7 +557,11 @@ tcp_port_monitor_t * create_tcp_port_monitor(
/* create the monitor's connection hash */ /* create the monitor's connection hash */
if ( hash_create( &p_monitor->hash, if ( hash_create( &p_monitor->hash,
hash_size > 0 ? hash_size : TCP_CONNECTION_HASH_SIZE, p_creation_args && p_creation_args->min_port_monitor_connections > 0 ?
calc_efficient_hash_size( p_creation_args->min_port_monitor_connections,
TCP_CONNECTION_HASH_SIZE_MAX,
TCP_CONNECTION_HASH_MAX_LOAD_RATIO ) :
TCP_CONNECTION_HASH_SIZE_DEFAULT,
&connection_hash_function_1, &connection_hash_function_2, &connection_hash_function_1, &connection_hash_function_2,
&connection_match_function, NULL ) != 0 ) &connection_match_function, NULL ) != 0 )
{ {
@ -536,7 +571,7 @@ tcp_port_monitor_t * create_tcp_port_monitor(
} }
/* create the monitor's peek array */ /* create the monitor's peek array */
if ( (p_monitor->p_peek = (tcp_connection_t **) calloc( TCP_CONNECTION_HASH_SIZE, sizeof(tcp_connection_t *))) == NULL ) if ( (p_monitor->p_peek = (tcp_connection_t **) calloc( p_monitor->hash.size, sizeof(tcp_connection_t *))) == NULL )
{ {
/* we failed to create the peek array, so destroy the monitor completely, again, so we don't leak */ /* we failed to create the peek array, so destroy the monitor completely, again, so we don't leak */
destroy_tcp_port_monitor(p_monitor,NULL); destroy_tcp_port_monitor(p_monitor,NULL);
@ -658,7 +693,7 @@ int peek_tcp_port_monitor(
/* Create a monitor collection. Do this one first. */ /* Create a monitor collection. Do this one first. */
tcp_port_monitor_collection_t * create_tcp_port_monitor_collection( tcp_port_monitor_collection_t * create_tcp_port_monitor_collection(
int hash_size tcp_port_monitor_collection_args_t * p_creation_args
) )
{ {
tcp_port_monitor_collection_t * p_collection; tcp_port_monitor_collection_t * p_collection;
@ -669,7 +704,11 @@ tcp_port_monitor_collection_t * create_tcp_port_monitor_collection(
/* create the collection's monitor hash */ /* create the collection's monitor hash */
if ( hash_create( &p_collection->hash, if ( hash_create( &p_collection->hash,
hash_size > 0 ? hash_size : TCP_MONITOR_HASH_SIZE, p_creation_args && p_creation_args->min_port_monitors > 0 ?
calc_efficient_hash_size( p_creation_args->min_port_monitors,
TCP_MONITOR_HASH_SIZE_MAX,
TCP_MONITOR_HASH_MAX_LOAD_RATIO ) :
TCP_MONITOR_HASH_SIZE_DEFAULT,
&monitor_hash_function_1, &monitor_hash_function_2, &monitor_hash_function_1, &monitor_hash_function_2,
&monitor_match_function, NULL ) != 0 ) &monitor_match_function, NULL ) != 0 )
{ {

View File

@ -23,6 +23,7 @@
#ifndef LIBTCP_PORTMON_H #ifndef LIBTCP_PORTMON_H
#define LIBTCP_PORTMON_H #define LIBTCP_PORTMON_H
#include <math.h>
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
@ -37,7 +38,7 @@
* Each port monitor contains a connection hash whose contents changes dynamically as the monitor * Each port monitor contains a connection hash whose contents changes dynamically as the monitor
* is presented with connections on each update cycle. This implementation maintains the health * is presented with connections on each update cycle. This implementation maintains the health
* of this hash by enforcing several rules. First, the hash cannot contain more items than the * of this hash by enforcing several rules. First, the hash cannot contain more items than the
* TCP_CONNECTION_HASH_MAX_LOAD_PCT permits. For example, a 256 element hash with a max load of * TCP_CONNECTION_HASH_MAX_LOAD_RATIO permits. For example, a 256 element hash with a max load of
* 0.5 cannot contain more than 128 connections. Additional connections are ignored by the monitor. * 0.5 cannot contain more than 128 connections. Additional connections are ignored by the monitor.
* The load factor of 0.5 is low enough to keep the hash running at near O(1) performanace at all * The load factor of 0.5 is low enough to keep the hash running at near O(1) performanace at all
* times. As elements are removed from the hash, the hash slots are tagged vacated, as required * times. As elements are removed from the hash, the hash slots are tagged vacated, as required
@ -46,14 +47,15 @@
* The problem with vacated slots (even though they are reused) is that, as they increase in number, * The problem with vacated slots (even though they are reused) is that, as they increase in number,
* esp. past about 1/4 of all slots, the average number of probes the hash has to perform increases * esp. past about 1/4 of all slots, the average number of probes the hash has to perform increases
* from O(1) on average to O(n) worst case. To keep the hash healthy, we simply rebuild it when the * from O(1) on average to O(n) worst case. To keep the hash healthy, we simply rebuild it when the
* percentage of vacated slots gets too high (above TCP_CONNECTION_HASH_MAX_VACATED_PCT). Rebuilding * percentage of vacated slots gets too high (above TCP_CONNECTION_HASH_MAX_VACATED_RATIO).
* the hash takes O(n) on the number of elements, but it well worth it as it keeps the hash running * Rebuilding the hash takes O(n) on the number of elements, but it well worth it as it keeps the
* at an average access time of O(1). * hash running at an average access time of O(1).
* ------------------------------------------------------------------------------------------------*/ * ------------------------------------------------------------------------------------------------*/
#define TCP_CONNECTION_HASH_SIZE 512 /* connection hash size -- must be a power of two */ #define TCP_CONNECTION_HASH_SIZE_DEFAULT 512 /* connection hash size default -- must be a power of two */
#define TCP_CONNECTION_HASH_MAX_LOAD_PCT 0.5 /* disallow inserts after this % load is exceeded */ #define TCP_CONNECTION_HASH_SIZE_MAX 65535 /* connection hash size maximum -- must be a power of two */
#define TCP_CONNECIION_HASH_MAX_VACATED_PCT 0.25 /* rebalance hash after this % of vacated slots is exceeded */ #define TCP_CONNECTION_HASH_MAX_LOAD_RATIO 0.5 /* disallow inserts after this load ratio is exceeded */
#define TCP_CONNECIION_HASH_MAX_VACATED_RATIO 0.25 /* rebalance hash after this ratio of vacated slots is exceeded */
#define TCP_CONNECIION_STARTING_AGE 1 /* connection deleted if unseen again after this # of refreshes */ #define TCP_CONNECIION_STARTING_AGE 1 /* connection deleted if unseen again after this # of refreshes */
/* ---------------------------------------------------------------------------------------- /* ----------------------------------------------------------------------------------------
@ -66,8 +68,9 @@
* lookups at O(1). * lookups at O(1).
* ----------------------------------------------------------------------------------------*/ * ----------------------------------------------------------------------------------------*/
#define TCP_MONITOR_HASH_SIZE 32 /* monitor hash size -- must be a power of two */ #define TCP_MONITOR_HASH_SIZE_DEFAULT 32 /* monitor hash size default -- must be a power of two */
#define TCP_MONITOR_HASH_MAX_LOAD_PCT 0.5 /* disallow new monitors after this % load is exceeded */ #define TCP_MONITOR_HASH_SIZE_MAX 512 /* monitor hash size maximum -- must be a power of two */
#define TCP_MONITOR_HASH_MAX_LOAD_RATIO 0.5 /* disallow new monitors after this load ratio is exceeded */
/* ------------------------------------------------------------------- /* -------------------------------------------------------------------
* IMPLEMENTATION INTERFACE * IMPLEMENTATION INTERFACE
@ -217,6 +220,14 @@ void for_each_tcp_port_monitor_in_collection(
void * /* p_function_args (for user arguments) */ void * /* p_function_args (for user arguments) */
); );
/* ----------------------------------------------------------------------------------------
* Calculate an efficient hash size based on the desired number of elements and load factor.
* ---------------------------------------------------------------------------------------- */
int calc_efficient_hash_size(
int /* min_elements, the minimum number of elements to store */,
int /* max_hash_size, the maximum permissible hash size */,
double /* max_load_factor, the fractional load we wish not to exceed, e.g. 0.5 */
);
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
* CLIENT INTERFACE * CLIENT INTERFACE
@ -224,6 +235,17 @@ void for_each_tcp_port_monitor_in_collection(
* Clients should call only those functions below this line. * Clients should call only those functions below this line.
* ---------------------------------------------------------------------- */ * ---------------------------------------------------------------------- */
/* struct to hold monitor creation arguments */
typedef struct _tcp_port_monitor_args_t {
int min_port_monitor_connections; /* monitor must support tracking at least this many connections */
} tcp_port_monitor_args_t;
/* struct to hold collection creation arguments */
typedef struct _tcp_port_monitor_collection_args_t {
int min_port_monitors; /* collection must support creation of at least this many monitors */
} tcp_port_monitor_collection_args_t;
/* ---------------------------------- /* ----------------------------------
* Client operations on port monitors * Client operations on port monitors
* ---------------------------------- */ * ---------------------------------- */
@ -233,7 +255,7 @@ void for_each_tcp_port_monitor_in_collection(
tcp_port_monitor_t * create_tcp_port_monitor( tcp_port_monitor_t * create_tcp_port_monitor(
in_port_t /* port_range_begin */, in_port_t /* port_range_begin */,
in_port_t /* port_range_end */, in_port_t /* port_range_end */,
int /* hash_size */ tcp_port_monitor_args_t * /* p_creation_args, NULL ok for library defaults */
); );
/* Clients use this function to get connection data from the indicated port monitor. /* Clients use this function to get connection data from the indicated port monitor.
@ -253,7 +275,7 @@ int peek_tcp_port_monitor(
/* Create a monitor collection. Do this one first. */ /* Create a monitor collection. Do this one first. */
tcp_port_monitor_collection_t * create_tcp_port_monitor_collection( tcp_port_monitor_collection_t * create_tcp_port_monitor_collection(
int /* hash_size */ tcp_port_monitor_collection_args_t * /* p_creation_args, NULL ok for library defaults */
); );
/* Destroy the monitor collection (and everything it contains). Do this one last. */ /* Destroy the monitor collection (and everything it contains). Do this one last. */

View File

@ -16,7 +16,7 @@ test-hash: test-hash.o hash.o
$(CC) $(CFLAGS) -o $@ test-hash.o hash.o $(CC) $(CFLAGS) -o $@ test-hash.o hash.o
test-portmon: test-portmon.o libtcp-portmon.o hash.o test-portmon: test-portmon.o libtcp-portmon.o hash.o
$(CC) $(CFLAGS) -o $@ test-portmon.o libtcp-portmon.o hash.o $(CC) $(CFLAGS) -o $@ test-portmon.o libtcp-portmon.o hash.o -lm
test-hash.o: test-hash.c hash.h test-hash.o: test-hash.c hash.h
test-portmon.o: test-portmon.c libtcp-portmon.h hash.h test-portmon.o: test-portmon.c libtcp-portmon.h hash.h

View File

@ -25,12 +25,12 @@ int main()
(void) signal(SIGINT,set_terminate); (void) signal(SIGINT,set_terminate);
if ( (p_collection = create_tcp_port_monitor_collection( 0 )) == NULL) { if ( (p_collection = create_tcp_port_monitor_collection( NULL )) == NULL) {
fprintf(stderr,"error: create_tcp_port_monitor_collection()\n"); fprintf(stderr,"error: create_tcp_port_monitor_collection()\n");
exit(1); exit(1);
} }
if ( (p_monitor = create_tcp_port_monitor( 1, 65535, 0 )) == NULL) { if ( (p_monitor = create_tcp_port_monitor( 1, 65535, NULL )) == NULL) {
fprintf(stderr,"error: create_tcp_port_monitor()\n"); fprintf(stderr,"error: create_tcp_port_monitor()\n");
exit(1); exit(1);
} }