On 04/16/12 09:54, Bruce Korb wrote:
I suppose the motivation is performance?
If so, have you measured the improvement?

Actually, no, it is not for performance. I found it wearisome to write:

But curiosity got the better of me:

$ ./timer
strpbrk    startup time:     0.000 run time:       31.081
macros     startup time:     0.000 run time:       19.882
#define _GNU_SOURCE 1
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>

#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "timer-map.h"

#define START_CT 1000
#define FULL_CT  (1000 * 1000 * 1000)

typedef struct {
    struct timeval start, middle, end;
} race_times_t;

volatile char extern_ch;
char const * text = NULL;

void
print_timings(race_times_t * pb, race_times_t * mac);

void
use_strpbrk(int ct)
{
    while (ct-- > 0) {
        char * p = strpbrk(text, "#~");
        extern_ch = *p;
    }
}

void
use_macros(int ct)
{
    while (ct-- > 0) {
        char * p = SPN_HASH_CHARS(text);
        extern_ch = *p;
    }
}

void
map_file(char const * fname)
{
    struct stat sb;
    int sres = stat(fname, &sb);
    int fd   = open(fname, O_RDONLY);
    void * map = mmap(NULL, sb.st_size+1, PROT_READ, MAP_SHARED, fd, 0);
    if ((sres < 0) || (fd < 0) || (map == MAP_FAILED))
        exit(1);
    text = map;
}

int
main(int argc, char ** argv)
{
    race_times_t for_strpbrk;
    race_times_t for_macros;

    {
        char const * fn = argv[1] ? argv[1] : __FILE__;
        map_file(fn);
    }

    gettimeofday(&for_strpbrk.start, NULL);
    use_strpbrk(START_CT);
    gettimeofday(&for_strpbrk.middle, NULL);
    use_strpbrk(FULL_CT);
    gettimeofday(&for_strpbrk.end, NULL);

    for_macros.start = for_strpbrk.end;
    use_macros(START_CT);
    gettimeofday(&for_macros.middle, NULL);
    use_macros(FULL_CT);
    gettimeofday(&for_macros.end, NULL);

    print_timings(&for_strpbrk, &for_macros);
    return 0;
}

int
delta(struct timeval * s, struct timeval * e)
{
    if (s->tv_sec == e->tv_sec)
        return (500 + e->tv_usec - s->tv_usec) / 1000;
    int msec = (500 + (1000000 - s->tv_usec) + e->tv_usec) / 1000;
    return msec + ((e->tv_sec - s->tv_sec) - 1) * 1000;
}

void
fmtnum(char * buf, int msec)
{
    int len = sprintf(buf, "%04u", msec);
    char * p = buf + len - 3;
    memmove(p+1, p, 4);
    *p = '.';
}

void
print_timings(race_times_t * pb, race_times_t * mac)
{
    static char const fmt[] =
        "%-10s startup time: %9s run time: %12s\n";

    int delta1 = delta(&pb->start,  &pb->middle);
    int delta2 = delta(&pb->middle, &pb->end);
    char buf1[32], buf2[32];
    fmtnum(buf1, delta1);
    fmtnum(buf2, delta2);
    printf(fmt, "strpbrk", buf1, buf2);

    delta1 = delta(&mac->start,  &mac->middle);
    delta2 = delta(&mac->middle, &mac->end);
    fmtnum(buf1, delta1);
    fmtnum(buf2, delta2);
    printf(fmt, "macros", buf1, buf2);
}
/*
 *  1 bit character mapping generated 04/16/12 10:12:44
 *
 *  char-mapper Character Classifications
 */
#ifndef TIMER_MAP_H_GUARD
#define TIMER_MAP_H_GUARD 1

#ifdef HAVE_CONFIG_H
# if defined(HAVE_INTTYPES_H)
#   include <inttypes.h>

# elif defined(HAVE_STDINT_H)
#   include <stdint.h>

#   elif !defined(HAVE_UINT8_T)
        typedef unsigned char   uint8_t;
# endif /* HAVE_*INT*_H header */

#else /* not HAVE_CONFIG_H -- */
# include <inttypes.h>
#endif /* HAVE_CONFIG_H */

#if 0 /* mapping specification source (from timer-map.map) */
// 
// %guard
// %file           timer-map.h
// %backup
// 
// hash   "#~"
//
#endif /* 0 -- mapping spec. source */


typedef uint8_t timer_map_mask_t;

#define  IS_HASH_CHAR( _c)   is_timer_map_char((char)( _c), 0x01)
#define SPN_HASH_CHARS(_s)  spn_timer_map_chars((char *)_s, 0x01)
#define BRK_HASH_CHARS(_s)  brk_timer_map_chars((char *)_s, 0x01)
#define SPN_HASH_BACK(s,e)  spn_timer_map_back((char *)s, (char *)e, 0x01)
#define BRK_HASH_BACK(s,e)  brk_timer_map_back((char *)s, (char *)e, 0x01)

static timer_map_mask_t const timer_map_table[128] = {
  /*NUL*/ 0x00, /*x01*/ 0x00, /*x02*/ 0x00, /*x03*/ 0x00,
  /*x04*/ 0x00, /*x05*/ 0x00, /*x06*/ 0x00, /*BEL*/ 0x00,
  /* BS*/ 0x00, /* HT*/ 0x00, /* NL*/ 0x00, /* VT*/ 0x00,
  /* FF*/ 0x00, /* CR*/ 0x00, /*x0E*/ 0x00, /*x0F*/ 0x00,
  /*x10*/ 0x00, /*x11*/ 0x00, /*x12*/ 0x00, /*x13*/ 0x00,
  /*x14*/ 0x00, /*x15*/ 0x00, /*x16*/ 0x00, /*x17*/ 0x00,
  /*x18*/ 0x00, /*x19*/ 0x00, /*x1A*/ 0x00, /*ESC*/ 0x00,
  /*x1C*/ 0x00, /*x1D*/ 0x00, /*x1E*/ 0x00, /*x1F*/ 0x00,
  /*   */ 0x00, /* ! */ 0x00, /* " */ 0x00, /* # */ 0x01,
  /* $ */ 0x00, /* % */ 0x00, /* & */ 0x00, /* ' */ 0x00,
  /* ( */ 0x00, /* ) */ 0x00, /* * */ 0x00, /* + */ 0x00,
  /* , */ 0x00, /* - */ 0x00, /* . */ 0x00, /* / */ 0x00,
  /* 0 */ 0x00, /* 1 */ 0x00, /* 2 */ 0x00, /* 3 */ 0x00,
  /* 4 */ 0x00, /* 5 */ 0x00, /* 6 */ 0x00, /* 7 */ 0x00,
  /* 8 */ 0x00, /* 9 */ 0x00, /* : */ 0x00, /* ; */ 0x00,
  /* < */ 0x00, /* = */ 0x00, /* > */ 0x00, /* ? */ 0x00,
  /* @ */ 0x00, /* A */ 0x00, /* B */ 0x00, /* C */ 0x00,
  /* D */ 0x00, /* E */ 0x00, /* F */ 0x00, /* G */ 0x00,
  /* H */ 0x00, /* I */ 0x00, /* J */ 0x00, /* K */ 0x00,
  /* L */ 0x00, /* M */ 0x00, /* N */ 0x00, /* O */ 0x00,
  /* P */ 0x00, /* Q */ 0x00, /* R */ 0x00, /* S */ 0x00,
  /* T */ 0x00, /* U */ 0x00, /* V */ 0x00, /* W */ 0x00,
  /* X */ 0x00, /* Y */ 0x00, /* Z */ 0x00, /* [ */ 0x00,
  /* \ */ 0x00, /* ] */ 0x00, /* ^ */ 0x00, /* _ */ 0x00,
  /* ` */ 0x00, /* a */ 0x00, /* b */ 0x00, /* c */ 0x00,
  /* d */ 0x00, /* e */ 0x00, /* f */ 0x00, /* g */ 0x00,
  /* h */ 0x00, /* i */ 0x00, /* j */ 0x00, /* k */ 0x00,
  /* l */ 0x00, /* m */ 0x00, /* n */ 0x00, /* o */ 0x00,
  /* p */ 0x00, /* q */ 0x00, /* r */ 0x00, /* s */ 0x00,
  /* t */ 0x00, /* u */ 0x00, /* v */ 0x00, /* w */ 0x00,
  /* x */ 0x00, /* y */ 0x00, /* z */ 0x00, /* { */ 0x00,
  /* | */ 0x00, /* } */ 0x00, /* ~ */ 0x01, /*x7F*/ 0x00
};
static inline int
is_timer_map_char(char ch, timer_map_mask_t mask)
{
    unsigned int ix = (unsigned char)ch;
    return ((ix < 128) && ((timer_map_table[ix] & mask) != 0));
}

static inline char *
spn_timer_map_chars(char * p, timer_map_mask_t mask)
{
    while ((*p != '\0') && is_timer_map_char(*p, mask))  p++;
    return p;
}

static inline char *
brk_timer_map_chars(char * p, timer_map_mask_t mask)
{
    while ((*p != '\0') && (! is_timer_map_char(*p, mask)))  p++;
    return p;
}

static inline char *
spn_timer_map_back(char * s, char * e, timer_map_mask_t mask)
{
    if (s == e) e += strlen(e);
    while ((e > s) && is_timer_map_char(e[-1], mask))  e--;
    return e;
}

static inline char *
brk_timer_map_back(char * s, char * e, timer_map_mask_t mask)
{
    if (s == e) e += strlen(e);
    while ((e > s) && (! is_timer_map_char(e[-1], mask)))  e--;
    return e;
}
#endif /* TIMER_MAP_H_GUARD */

Reply via email to