Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

abのベンチをあげるコード

昨日ぐらいからcpu profilerと戦いつつ、うんうん考えてた方法。
思いついた方法と同じような事をnginxもやってて「やっぱそうなるのか」といった感じ。
で頂きました。
ぶっちゃけインチキコードじゃないかなあと思う。

とりあえず、時間を引っぱる処理はそれなりにもっていかれるのでそれをいかに少なくするかという話。
(localtimeがCPUを持っていく)
つーかあってるのかも微妙な感じだけど。

time_cache.h

typedef struct {
    time_t      sec;
    uintptr_t  msec;
    int   gmtoff;
} cache_time_t;

void
cache_time_init(void);

void
cache_time_update(void);

extern volatile char    *err_log_time;
extern volatile char    *http_time;
extern volatile char    *http_log_time;

time_cache.c

#include <inttypes.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>

#include "time_cache.h"
#include "atomic.h"

#define TIME_SLOTS   64

static uintptr_t        slot;

volatile uintptr_t      current_msec;
volatile cache_time_t     *_cached_time;
volatile char       *err_log_time;
volatile char       *http_time;
volatile char       *http_log_time;

static cache_time_t        cached_time[TIME_SLOTS];
static char            cached_err_log_time[TIME_SLOTS]
                                    [sizeof("1970/09/28 12:00:00")];
static char            cached_http_time[TIME_SLOTS]
                                    [sizeof("Mon, 28 Sep 1970 06:00:00 GMT")];
static char            cached_http_log_time[TIME_SLOTS]
                                    [sizeof("28/Sep/1970:12:00:00 +0600")];


static char  *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static char  *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

void
cache_time_init(void)
{

    _cached_time = &cached_time[0];

    cache_time_update();
}


#define get_timezone(isdst) (- (isdst ? timezone + 3600 : timezone) / 60)

void
cache_time_update(void)
{
    time_t sec = 0;
    uintptr_t msec = 0;
    char          *p0, *p1, *p2;
    cache_time_t      *tp;
    struct timeval   tv;
    
    
    gettimeofday(&tv, NULL);

    sec = tv.tv_sec;
    msec = tv.tv_usec / 1000;

    current_msec = (uintptr_t) sec * 1000 + msec;

    tp = &cached_time[slot];

    if (tp->sec == sec) {
        tp->msec = msec;
        return;
    }

    if (slot == TIME_SLOTS - 1) {
        slot = 0;
    } else {
        slot++;
    }

    tp = &cached_time[slot];

    tp->sec = sec;
    tp->msec = msec;

	time_t tt = time(NULL);
    struct tm* gmt = gmtime(&tt);

    p0 = &cached_http_time[slot][0];

    sprintf(p0, "%s, %02d %s %4d %02d:%02d:%02d GMT",
                       week[gmt->tm_wday], gmt->tm_mday,
                       months[gmt->tm_mon], gmt->tm_year + 1900,
                       gmt->tm_hour, gmt->tm_min, gmt->tm_sec);

    struct tm* p = localtime(&tt);
    p->tm_mon++;
    p->tm_year += 1900;
    tp->gmtoff = get_timezone(p->tm_isdst);

    p1 = &cached_err_log_time[slot][0];

    sprintf(p1, "%4d/%02d/%02d %02d:%02d:%02d",
                       p->tm_year, p->tm_mon,
                       p->tm_mday, p->tm_hour,
                       p->tm_min, p->tm_sec);

    p2 = &cached_http_log_time[slot][0];

    sprintf(p2, "%02d/%s/%d:%02d:%02d:%02d %c%02d%02d",
                       p->tm_mday, months[p->tm_mon - 1],
                       p->tm_year, p->tm_hour,
                       p->tm_min, p->tm_sec,
                       tp->gmtoff < 0 ? '-' : '+',
                       abs(tp->gmtoff / 60), abs(tp->gmtoff % 60));


    _cached_time = tp;
    http_time = p0;
    err_log_time = p1;
    http_log_time = p2;

}

Dateヘッダやアクセスログに出す時間は秒単位なので秒が変わらない間はキャッシュしてる値を使い回すという作戦。
abのように短時間にひたすらさばき続けないといけないケースで効果がある。
まあ実運用になるとどうなの?って感じもするけど。。。