Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C logger, tries to minimize performance hit of logging

1 view
Skip to first unread message

Will Ware

unread,
Apr 18, 2008, 9:31:42 AM4/18/08
to
Posting via Google Groups, which mangles long lines. Manual repair of
shell archive may be needed.

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.6.3).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh20859
# Made on 2008-04-18 09:24 EDT by <wware@nanorex-laptop>.
# Source directory was `/home/wware/clog'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 3460 -rw-r--r-- clog.c
# 223 -rw-r--r-- clog.h
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU
coreutils.'
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
if test "$gettext_dir" = FAILED && test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir ;;
esac
fi
if test "$locale_dir" = FAILED && test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
echo=echo
else
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'

else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and'
${echo} 'installing GNU `touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir}
then : ; else ${echo} 'lock directory '${lock_dir}' exists'
exit 1
fi
if mkdir ${lock_dir}
then ${echo} 'x - created lock directory `'${lock_dir}\''.'
else ${echo} 'x - failed to create lock directory `'${lock_dir}\''.'
exit 1
fi
# ============= clog.c ==============
if test -f 'clog.c' && test "$first_param" != -c; then
${echo} 'x -SKIPPING clog.c (file already exists)'
else
${echo} 'x - extracting clog.c (text)'
sed 's/^X//' << 'SHAR_EOF' > 'clog.c' &&
/*
X * C logger, tries to minimize performance hit of logging a message.
X * Potentially useful in embedded systems.
X *
X * gcc -o clog clog.c -lrt
X */
X
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <malloc.h>
#include <semaphore.h>
X
static sem_t clog_list_sync;
static int clog_list_ready = 0;
X
struct clog_list_entry {
X char *filename;
X int linenumber;
X char *message;
X int value;
};
#define CLOG_LISTSIZE 1000
struct clog_list_entry clog_list[CLOG_LISTSIZE];
static int clog_read_pointer = 0;
static int clog_write_pointer = 0;
static int kill_clog_thread = 0;
X
static inline int claim_lock(void)
{
X return sem_wait(&clog_list_sync);
}
X
static inline void release_lock(void)
{
X sem_post(&clog_list_sync);
}
X
/* calls to this must be protected by claim and release */
static int clog_list_size(void)
{
X int x;
X x = clog_write_pointer - clog_read_pointer;
X while (x < 0) x += CLOG_LISTSIZE;
X while (x >= CLOG_LISTSIZE) x -= CLOG_LISTSIZE;
X return x;
}
X
static inline void print_right_justified(char *str)
{
X static const char *thirty_spaces = " ";
X if (str == NULL) return;
X int n = strlen(str);
X if (n > 30) n = 30;
X printf("%s", thirty_spaces + n);
X printf("%s", str);
}
X
static void *clog_print_thread(void *data)
{
X (void) data;
X while (!kill_clog_thread) {
X if (claim_lock() != 0) break;
X if (clog_list_size() > 0) {
X if (clog_list[clog_read_pointer].filename != NULL) {
X if (1) {
X print_right_justified(clog_list[clog_read_pointer].filename);
X printf(":%d\t", clog_list[clog_read_pointer].linenumber);
X }
X print_right_justified(clog_list[clog_read_pointer].message);
X printf(" %12d %010p\n", clog_list[clog_read_pointer].value,
clog_list[clog_read_pointer].value);
X } else {
X printf(" * * * * C logger dropped %d messages * * * *\n",
X clog_list[clog_read_pointer].linenumber);
X }
X clog_read_pointer = (clog_read_pointer + 1) % CLOG_LISTSIZE;
X }
X release_lock();
X }
X return data;
}
X
void put_clog_message(char *filename, int linenumber, char *message,
int value)
{
X if (!clog_list_ready) {
X pthread_t thr;
X sem_init(&clog_list_sync, 0, 1);
X pthread_create(&thr, NULL, clog_print_thread, NULL);
X clog_list_ready = 1;
X }
X if (claim_lock() != 0) return;
X if (clog_list_size() < CLOG_LISTSIZE - 2) {
X // store a message if there is room for it
X clog_list[clog_write_pointer].filename = filename;
X clog_list[clog_write_pointer].linenumber = linenumber;
X clog_list[clog_write_pointer].message = message;
X clog_list[clog_write_pointer].value = value;
X clog_write_pointer = (clog_write_pointer + 1) % CLOG_LISTSIZE;
X } else {
X // otherwise store a single message telling how many were dropped
X int previous_write =
X (clog_write_pointer + CLOG_LISTSIZE - 1) % CLOG_LISTSIZE;
X if (clog_list[previous_write].filename != NULL) {
X clog_list[clog_write_pointer].filename = NULL;
X clog_list[clog_write_pointer].linenumber = 1;
X clog_list[clog_write_pointer].message = NULL;
X clog_list[clog_write_pointer].value = 0;
X clog_write_pointer = (clog_write_pointer + 1) % CLOG_LISTSIZE;
X } else {
X // single message already stored, increment number dropped
X clog_list[previous_write].linenumber++;
X }
X }
X release_lock();
}
X
#if (!DANGER)
#include "clog.h"
X
int main(void)
{
X int i, pi = 314159;
X for (i = 0; i < 100000; i++) {
X SAY(pi);
X SAY(pi + pi);
X SAY(pi * pi + pi);
X SAY(pi + pi + pi + pi + pi + pi + pi);
X }
X sleep(1);
}
#endif
SHAR_EOF
(set 20 08 04 18 09 23 37 'clog.c'; eval "$shar_touch") &&
chmod 0644 'clog.c'
if test $? -ne 0
then ${echo} 'restore of clog.c failed'
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'clog.c: MD5 check
failed'
) << SHAR_EOF
5016414e110392976ff5028ca46c2821 clog.c
SHAR_EOF
else
test `LC_ALL=C wc -c < 'clog.c'` -ne 3460 && \
${echo} 'restoration warning: size of clog.c is not 3460'
fi
fi
# ============= clog.h ==============
if test -f 'clog.h' && test "$first_param" != -c; then
${echo} 'x -SKIPPING clog.h (file already exists)'
else
${echo} 'x - extracting clog.h (text)'
sed 's/^X//' << 'SHAR_EOF' > 'clog.h' &&
/*
X * C logger
X */
extern void put_clog_message(char *filename, int linenumber, char
*message, int value);
#define DBGMSG(msg,val) put_clog_message(__FILE__, __LINE__, msg,
(val))
#define VALUE(val) DBGMSG(#val,val)
SHAR_EOF
(set 20 08 04 18 09 24 05 'clog.h'; eval "$shar_touch") &&
chmod 0644 'clog.h'
if test $? -ne 0
then ${echo} 'restore of clog.h failed'
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'clog.h: MD5 check
failed'
) << SHAR_EOF
1982be80e41e560db2cadd3251fcbfe7 clog.h
SHAR_EOF
else
test `LC_ALL=C wc -c < 'clog.h'` -ne 223 && \
${echo} 'restoration warning: size of clog.h is not 223'
fi
fi
if rm -fr ${lock_dir}
then ${echo} 'x - removed lock directory `'${lock_dir}\''.'
else ${echo} 'x - failed to remove lock directory `'${lock_dir}\''.'
exit 1
fi
exit 0

Will Ware

unread,
Apr 19, 2008, 12:42:08 AM4/19/08
to
After a few more refinements.
==== clog.c ====
/* -*- Mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -
*-
*
* This logger attempts to have minimal impact on the code from which
* messages are logged.
*

* gcc -o clog clog.c -lrt
*/

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <malloc.h>
#include <semaphore.h>

#include "clog.h"

static pthread_t clog_thread;
static sem_t clog_list_sync;
static unsigned char clog_init_done = 0;

struct clog_list_entry {
char *filename;
int linenumber;
char *message;
int value;
};
#define CLOG_LISTSIZE 100000


struct clog_list_entry clog_list[CLOG_LISTSIZE];
static int clog_read_pointer = 0;
static int clog_write_pointer = 0;

static const char *thirty_spaces = " ";

/* calls to this must be protected by the semaphore */
static int clog_list_size(void)
{
return (clog_write_pointer + CLOG_LISTSIZE - clog_read_pointer)
% CLOG_LISTSIZE;
}

static inline void print_right_justified(char *str)
{

if (str == NULL) return;

int n = strlen(str);


if (n > 30) n = 30;

printf("%s", thirty_spaces + n);

printf("%s", str);
}

static void *clog_print_thread(void *data)
{
(void) data;
while (1) {
if (sem_wait(&clog_list_sync) != 0) break;
if (clog_list_size() > 0) {
struct clog_list_entry myentry = clog_list[clog_read_pointer];


clog_read_pointer = (clog_read_pointer + 1) % CLOG_LISTSIZE;

sem_post(&clog_list_sync);
if (myentry.filename != NULL) {
print_right_justified(myentry.filename);
printf(":%d\t", myentry.linenumber);
print_right_justified(myentry.message);
printf(" %12d %10p\n", myentry.value, (void*) myentry.value);
} else {


printf(" * * * * C logger dropped %d messages * * * *\n",

myentry.linenumber);
}
} else {
sem_post(&clog_list_sync);
usleep(100000);
}
}
return data;
}

void clog_init(void)
{
sem_init(&clog_list_sync, 0, 1);
pthread_create(&clog_thread, NULL, clog_print_thread, NULL);
clog_init_done = 1;
}

void put_clog_message(char *filename, int linenumber, char *message,
int value)
{

if (!clog_init_done) return;
if (sem_wait(&clog_list_sync) != 0) return;


if (clog_list_size() < CLOG_LISTSIZE - 2) {

// store a message if there is room for it

clog_list[clog_write_pointer].filename = filename;

clog_list[clog_write_pointer].linenumber = linenumber;

clog_list[clog_write_pointer].message = message;

clog_list[clog_write_pointer].value = value;

clog_write_pointer = (clog_write_pointer + 1) % CLOG_LISTSIZE;

} else {


// otherwise store a single message telling how many were dropped

int previous_write =


(clog_write_pointer + CLOG_LISTSIZE - 1) % CLOG_LISTSIZE;

if (clog_list[previous_write].filename != NULL) {

clog_list[clog_write_pointer].filename = NULL;

clog_list[clog_write_pointer].linenumber = 1;

clog_list[clog_write_pointer].message = NULL;

clog_list[clog_write_pointer].value = 0;

clog_write_pointer = (clog_write_pointer + 1) % CLOG_LISTSIZE;

} else {


// single message already stored, increment number dropped

clog_list[previous_write].linenumber++;
}
}
sem_post(&clog_list_sync);
}

/* ============== Example usage ================ */

int main(void)
{


int i, pi = 314159;

clog_init();


for (i = 0; i < 100000; i++) {

SAY(pi);
SAY(pi + pi);


SAY(pi * pi + pi);

SAY(pi + pi + pi + pi + pi + pi + pi);
}

sleep(1);
}
==== clog.h ====


extern void put_clog_message(char *filename, int linenumber, char
*message, int value);

#define LOG(msg,val) put_clog_message(__FILE__, __LINE__, msg,
(val))
#define SAY(val) LOG(#val,val)

0 new messages