1
0
mirror of https://github.com/Llewellynvdm/conky.git synced 2024-12-24 11:55:43 +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;
#ifdef TCP_PORT_MONITOR
static int min_port_monitors = 0; /* config item */
static int min_port_monitor_connections = 0; /* config item */
tcp_port_monitor_collection_args_t tcp_port_monitor_collection_args;
tcp_port_monitor_args_t tcp_port_monitor_args;
#endif
/* 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 ( !info.p_tcp_port_monitor_collection )
{
double hash_size, log_base_2;
/* 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 );
info.p_tcp_port_monitor_collection =
create_tcp_port_monitor_collection( &tcp_port_monitor_collection_args );
if ( !info.p_tcp_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 ( 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 =
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 )
{
CRIT_ERR("tcp_portmon: unable to create port monitor");
@ -4507,8 +4486,8 @@ static void set_default_configurations(void)
#endif
#ifdef TCP_PORT_MONITOR
min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
tcp_port_monitor_collection_args.min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
tcp_port_monitor_args.min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
#endif
}
@ -4919,20 +4898,20 @@ else if (strcasecmp(name, a) == 0 || strcasecmp(name, b) == 0)
CONF("min_port_monitors")
{
if ( !value ||
(sscanf(value, "%d", &min_port_monitors) != 1) ||
min_port_monitors <= 0 )
(sscanf(value, "%d", &tcp_port_monitor_collection_args.min_port_monitors) != 1) ||
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("min_port_monitor_connections")
{
if ( !value ||
(sscanf(value, "%d", &min_port_monitor_connections) != 1)
|| min_port_monitor_connections <= 0 )
(sscanf(value, "%d", &tcp_port_monitor_args.min_port_monitor_connections) != 1)
|| 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;
}
}

View File

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

View File

@ -328,7 +328,7 @@ void maintain_tcp_port_monitor_hash(
#ifdef HASH_DEBUG
fprintf(stderr,"--- num vacated is %d, vacated factor is %.3f\n", p_monitor->hash.vacated, vacated_load );
#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 */
return;
@ -371,7 +371,7 @@ void rebuild_tcp_port_monitor_peek_table(
return;
/* 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++ )
{
@ -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
* 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" */
return;
@ -498,7 +498,38 @@ 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
*
@ -514,7 +545,7 @@ void for_each_tcp_port_monitor_in_collection(
tcp_port_monitor_t * create_tcp_port_monitor(
in_port_t port_range_begin,
in_port_t port_range_end,
int hash_size
tcp_port_monitor_args_t * p_creation_args
)
{
tcp_port_monitor_t * p_monitor;
@ -526,7 +557,11 @@ tcp_port_monitor_t * create_tcp_port_monitor(
/* create the monitor's connection 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_match_function, NULL ) != 0 )
{
@ -536,7 +571,7 @@ tcp_port_monitor_t * create_tcp_port_monitor(
}
/* 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 */
destroy_tcp_port_monitor(p_monitor,NULL);
@ -658,7 +693,7 @@ int peek_tcp_port_monitor(
/* Create a monitor collection. Do this one first. */
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;
@ -669,7 +704,11 @@ tcp_port_monitor_collection_t * create_tcp_port_monitor_collection(
/* create the collection's monitor 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_match_function, NULL ) != 0 )
{

View File

@ -23,6 +23,7 @@
#ifndef LIBTCP_PORTMON_H
#define LIBTCP_PORTMON_H
#include <math.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@ -37,7 +38,7 @@
* 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
* 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.
* 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
@ -46,14 +47,15 @@
* 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
* 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
* the hash takes O(n) on the number of elements, but it well worth it as it keeps the hash running
* at an average access time of O(1).
* percentage of vacated slots gets too high (above TCP_CONNECTION_HASH_MAX_VACATED_RATIO).
* Rebuilding the hash takes O(n) on the number of elements, but it well worth it as it keeps the
* 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_MAX_LOAD_PCT 0.5 /* disallow inserts after this % load is exceeded */
#define TCP_CONNECIION_HASH_MAX_VACATED_PCT 0.25 /* rebalance hash after this % of vacated slots is exceeded */
#define TCP_CONNECTION_HASH_SIZE_DEFAULT 512 /* connection hash size default -- must be a power of two */
#define TCP_CONNECTION_HASH_SIZE_MAX 65535 /* connection hash size maximum -- must be a power of two */
#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 */
/* ----------------------------------------------------------------------------------------
@ -66,8 +68,9 @@
* lookups at O(1).
* ----------------------------------------------------------------------------------------*/
#define TCP_MONITOR_HASH_SIZE 32 /* monitor hash size -- 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_DEFAULT 32 /* monitor hash size default -- must be a power of two */
#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
@ -217,6 +220,14 @@ void for_each_tcp_port_monitor_in_collection(
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
@ -224,6 +235,17 @@ void for_each_tcp_port_monitor_in_collection(
* 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
* ---------------------------------- */
@ -233,7 +255,7 @@ void for_each_tcp_port_monitor_in_collection(
tcp_port_monitor_t * create_tcp_port_monitor(
in_port_t /* port_range_begin */,
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.
@ -253,7 +275,7 @@ int peek_tcp_port_monitor(
/* Create a monitor collection. Do this one first. */
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. */

View File

@ -16,7 +16,7 @@ test-hash: test-hash.o hash.o
$(CC) $(CFLAGS) -o $@ test-hash.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-portmon.o: test-portmon.c libtcp-portmon.h hash.h

View File

@ -25,12 +25,12 @@ int main()
(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");
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");
exit(1);
}