Debug Macro

공부/C 2008. 11. 1. 00:47


내가 만든 로그 매크로 ...

/*
2008 02/15 - dbg_log() support stdout and file out

2010 08/11 - thread safe 지원, dbg_log() support syslog
             BSD License 지정

2010 09/05 - modify wrong print time
             modify wrong unsetTrace() proto type
             modify _AUGMENT_MSG format and order
             add printing thread id in _AUGMENT_MSG
             add weak symbols for multi definition global variable
             add checking wrong directive case
             support c89 standard without thread safe case

2011 01/02 - modify logout module to be run as atomic
             (before printing, aggregate all text in a buffer)
             add pid, tid, processname filter
             add DEBUG_EXT_# Policies
*/

/*
  Copyright (c) <2010>, <copyright initproc@gmail.com>
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
  1. Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
  3. All advertising materials mentioning features or use of this software
     must display the following acknowledgement:
     This product includes software developed by the <initproc@gmail.com>.
  4. Neither the name of the <initproc@gmail.com> nor the
     names of its contributors may be used to endorse or promote products
     derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY <initproc@gmail.com> ''AS IS'' AND ANY
  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL <initproc@gmail.com> BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DEBUG_LOG_MODULE
#define _DEBUG_LOG_MODULE

#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>

#ifdef _DEBUG_THREAD_SAFE
#include <pthread.h>
#define _GNU_SOURCE        /* or _BSD_SOURCE or _SVID_SOURCE */
#include <unistd.h>
#endif

#include <sys/syscall.h>   /* For SYS_xxx definitions */

/* debug run policy */
/* #define _DEBUG */

/* Apply debug codes to be thread safe */
/* #define _DEBUG_THREAD_SAFE  */

#if !defined(_DEBUG) && defined(_DEBUG_THREAD_SAFE)
#error "_DEBUG must be set if _DEBUG_THREAD_SAFE defined"
#endif

/* debug level policy */
#define DEBUG_ALL    INT_MAX
#define DEBUG_NONE   0
#define DEBUG_INFO   1
#define DEBUG_EXCEPT 2
#define DEBUG_ERROR  4
#define DEBUG_FATAL  8
#define DEBUG_EXT_1  16
#define DEBUG_EXT_2  32
#define DEBUG_EXT_3  64

#define DEFAULT_DEBUG_LEVEL DEBUG_ALL

pid_t pid_filter __attribute__((weak)) = -1;
pid_t tid_filter __attribute__((weak)) = -1;
char *process_filter __attribute__((weak)) = NULL;
char *process_name __attribute__((weak)) = NULL;

/* debug level */
unsigned int dbg_lv __attribute__((weak)) = DEFAULT_DEBUG_LEVEL;

/* debug print mode */
#define PRINT_MODE_STDOUT 1
#define PRINT_MODE_FILE   2
#define PRINT_MODE_SYSLOG 3
unsigned char print_mode __attribute__((weak)) = PRINT_MODE_STDOUT;

/* for logging out to file */
FILE *dbg_fp __attribute__((weak)) = NULL;

#ifdef _DEBUG_THREAD_SAFE
    pthread_rwlock_t dbg_lock __attribute__((weak)) = PTHREAD_RWLOCK_INITIALIZER;
    #define dbg_write_lock(lock) pthread_rwlock_wrlock (lock);
    #define dbg_read_lock(lock) pthread_rwlock_rdlock (lock);
    #define dbg_read_unlock(lock) pthread_rwlock_unlock (lock);
    #define dbg_write_unlock(lock) pthread_rwlock_unlock (lock);
#else
    #define dbg_write_lock(lock)
    #define dbg_read_lock(lock)
    #define dbg_read_unlock(lock)
    #define dbg_write_unlock(lock)
#endif

/* augment message (thread id, time, file, func, line) */
#define _AUGMENT_MSG

#ifndef _DEBUG_THREAD_SAFE
#define loc_time(now, tm_arg) memcpy(tm_arg, localtime(now), sizeof(struct tm))
#else
#define loc_time(now, tm_arg) localtime_r(now, tm_arg)
#endif

#define now_str(buf, max) \
        do { \
            time_t now; \
            struct tm tm; \
            now = time (NULL); \
            loc_time(&now, &tm); \
            strftime (buf, max, "%H:%M:%S", &tm); \
        } while (0)

#ifdef _DEBUG_THREAD_SAFE
#define AUGMENT_LOG "tid(%ld):%s:%s():%d: "
#define AUGMENT_LOG_ARGS syscall (SYS_gettid), __FILE__, __func__, __LINE__
#else
#define AUGMENT_LOG "%s:%s():%d: "
#define AUGMENT_LOG_ARGS __FILE__, __func__, __LINE__
#endif

static inline void setProcessname()
{
  FILE *fp = NULL;
  char pathbuf[PATH_MAX] = { 0x00,} , cmdline_buf[256] = { 0x00, };

  if (process_filter == NULL)
    return ;

  snprintf (pathbuf, sizeof(pathbuf), "/proc/%d/cmdline", getpid ());

  fp = fopen (pathbuf, "ro");

  if (fp == NULL)
    return ;

  fscanf (fp, "%s\n", cmdline_buf);

  fclose(fp);

  if (cmdline_buf[0])
  {
    if (process_name)
    {
      free (process_name);
      process_name = NULL;
    }

    if (process_name == NULL)
      process_name = strndup (cmdline_buf, 256);
  }
}

static inline void setProcessfilter(const char *name)
{
    dbg_write_lock(&dbg_lock);
    if (name)
    {
        if (process_filter)
        {
            free (process_filter);
            process_filter = NULL;
        }

        if (process_filter == NULL)
        {
            process_filter = strndup (name, 256);
            setProcessname ();
        }
    }
    dbg_write_unlock(&dbg_lock);
}

static inline int check_process_filter()
{
  if (strstr (process_name, process_filter) != NULL)
    return 1;

  return 0;
}

#ifdef _DEBUG
    #define setPidfilter(pid) \
    do { \
            dbg_write_lock(&dbg_lock); \
            pid_filter = pid; \
            dbg_write_unlock(&dbg_lock); \
    } while (0)

    #define setTidfilter(tid) \
    do { \
            dbg_write_lock(&dbg_lock); \
            tid_filter = tid; \
            dbg_write_unlock(&dbg_lock); \
    } while (0)

    #define setMode(mode) \
        do { \
            dbg_write_lock(&dbg_lock); \
            if (print_mode != mode) { \
                print_mode = mode; \
            } \
            dbg_write_unlock(&dbg_lock); \
        } while (0)

    #define setLevel(lv) \
        do { \
            dbg_write_lock(&dbg_lock); \
            dbg_lv = (lv); \
            dbg_write_unlock(&dbg_lock); \
        } while (0)

    #define setTrace(path, lv) \
        do { \
            dbg_write_lock(&dbg_lock); \
            if (path == NULL) { \
                if (dbg_fp)  { \
                    fclose(dbg_fp); \
                    dbg_fp = NULL; \
                } \
                print_mode = PRINT_MODE_STDOUT; \
            } else if (path) { \
                if (dbg_fp) { \
                    fclose(dbg_fp); \
                    dbg_fp = NULL; \
                }; \
                dbg_fp = fopen(path, "a"); \
                /* same as setlinebuf(xxx), use for compatible with c89 */ \
                setvbuf(dbg_fp, (char *)NULL, _IOLBF, 0); \
                print_mode = PRINT_MODE_FILE; \
            }; \
            dbg_lv = (lv); \
            dbg_write_unlock(&dbg_lock) \
        } while (0)

    #define unsetTrace() \
        do { \
            fclose (dbg_fp); \
            dbg_fp = NULL; \
            dbg_lv = 0; \
        } while (0)

    #ifdef _AUGMENT_MSG
        #define dbg_log(lv, fmt, args...) \
        do { \
            dbg_read_lock(&dbg_lock); \
            if (lv & dbg_lv) { \
                char buf[32] = { 0x00, }; \
                char txt_buffer[4096] = { 0x00, }; \
        if (pid_filter != -1 && getpid() != pid_filter) \
            break; \
        if (tid_filter != -1 && syscall (SYS_gettid) != tid_filter) \
            break; \
        if (process_filter != NULL && check_process_filter () == 0) \
            break; \
                if (dbg_fp && print_mode == PRINT_MODE_FILE) { \
                  now_str(buf, sizeof(buf)); \
          snprintf (txt_buffer, sizeof(txt_buffer), \
                  "%s:"AUGMENT_LOG fmt, buf, AUGMENT_LOG_ARGS, ##args); \
                  fprintf(dbg_fp, "%s", txt_buffer); \
                  fflush (dbg_fp); \
                } \
                else if (print_mode == PRINT_MODE_STDOUT) { \
                  now_str(buf, sizeof(buf)); \
          snprintf (txt_buffer, sizeof(txt_buffer), \
                  "%s:"AUGMENT_LOG fmt, buf, AUGMENT_LOG_ARGS, ##args); \
                  printf("%s", txt_buffer); \
                } \
                else if (print_mode == PRINT_MODE_SYSLOG) { \
                  now_str(buf, sizeof(buf)); \
          snprintf (txt_buffer, sizeof(txt_buffer), \
                  "%s:"AUGMENT_LOG fmt, buf, AUGMENT_LOG_ARGS, ##args); \
                  syslog(LOG_DEBUG, "%s", txt_buffer); \
                } \
             } \
            dbg_read_unlock(&dbg_lock); \
        } while (0)
    #else
        #define dbg_log(lv, fmt, args...)  \
        do { \
            dbg_read_lock(&dbg_lock); \
            if (lv & dbg_lv) { \
                if (dbg_fp && print_mode == PRINT_MODE_FILE) \
                    fprintf(dbg_fp, fmt, ##args); \
                else if (print_mode == PRINT_MODE_STDOUT) \
                    printf(fmt, ##args); \
                else if (print_mode == PRINT_MODE_SYSLOG)\
                    syslog(LOG_DEBUG, fmt, ##args); \
            } \
            dbg_read_unlock(&dbg_lock); \
        } while (0)
    #endif
#else
    #define setPidfilter(pid) \
    do { \
    } while (0)
    #define settidfilter(pid) \
    do { \
    } while (0)
    #define setMode(mode) \
    do { \
    } while (0)
    #define setTrace(path, lv) \
    do { \
    } while (0)
    #define unsetTrace() \
    do { \
    } while (0)
    #define setLevel(lv) \
    do { \
    } while (0)
    #define dbg_log(lv, fmt, args...) \
    do { \
    } while (0)
#endif

#endif

---------------



/*
Sampels..

Compile 1 (not safe in thread)
 gcc debug.c -lpthread -g -Wall -D_DEBUG

Compile 2 (thread safe)
  gcc debug.c -lpthread -g -Wall -D_DEBUG -D_DEBUG_THREAD_SAFE
*/

/* example */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define __USE_GNU
#include <pthread.h>
#undef __USE_GNU
#include <sched.h>

#include "debug.h"

void *thread_log (void *arg)
{
    int ret = 0, arg_val;
    srand(time(NULL));

    arg_val = (int)arg;

    while (1)
        {
            ret = rand() %  3;
            dbg_log (DEBUG_EXT_2,
                    "arg: %d,new thread log...\n",
                    arg_val);
            pthread_yield();
            sleep(ret);
        }
    return NULL;
}

int main(void)
{
    #if 0
    int bg = 0;
    setTrace (NULL, DEBUG_ALL); /* NULL (stdout) */

    dbg_log (DEBUG_INFO, "1 :[%s] [%d]\n", "kkk", bg);
    dbg_log (DEBUG_INFO, "2 :[%s] [%d]\n", "kkk", bg);

    setLevel (DEBUG_NONE); /* no logs anymore */
    dbg_log (DEBUG_INFO, "3 :[%s] [%d]\n", "kkk", bg);

    setTrace ("logfile", DEBUG_ALL); /* file path */
    dbg_log (DEBUG_INFO, "file_1 :[%s] [%d]\n", "kkk", bg);
    dbg_log (DEBUG_INFO, "file_2 :[%s] [%d]\n", "kkk", bg);

    setMode(PRINT_MODE_SYSLOG);

    dbg_log (DEBUG_INFO, "file_2 :[%s] [%d]\n", "kkk", bg);
    dbg_log (DEBUG_INFO, "file_1 :[%s] [%d]\n", "kkk", bg);

    setMode(PRINT_MODE_STDOUT);

    dbg_log (DEBUG_INFO, "file_2 :[%s] [%d]\n", "kkk", bg);
    dbg_log (DEBUG_INFO, "file_1 :[%s] [%d]\n", "kkk", bg);

    setMode(PRINT_MODE_FILE);
    dbg_log (DEBUG_INFO, "last change..\n");

    unsetTrace();
    #endif

    system ("rm -rf ./thread_log");
    setTrace ("thread_log", DEBUG_EXT_1 | DEBUG_EXT_2);

/*
    setProcessfilter ("a.out");
    setTidfilter (syscall(SYS_gettid));
*/

    pthread_t id_1, id_2, id_3, id_4, id_5;

    pthread_create (&id_1, NULL, thread_log, (void*)1);
    pthread_create (&id_2, NULL, thread_log, (void*)2);
    pthread_create (&id_3, NULL, thread_log, (void*)3);
    pthread_create (&id_4, NULL, thread_log, (void*)4);
    pthread_create (&id_5, NULL, thread_log, (void*)5);

    while (1)
    {
        dbg_log (DEBUG_EXT_1, "main thread log\n");
        pthread_yield();
    sleep (1);
    }

    return 0;
}

Posted by initproc
,

http://www.broadcom.com/support/802.11/linux_sta.php

Linux driver available for Dell Wireless cards

Christopher Tozzi's blog from Thursday reminded me of the announcement that I never made: Linux driver support is now available to Dell-branded wireless cards. We started working closely with Broadcom early this year on providing this support, as our customers have been asking for a Linux driver for our cards for a while now. As a result of this effort, Broadcom released an updated Linux wireless driver that supports cards based on the Broadcom 4311, 4312, 4321, and 4322 chipsets, which include the Dell 1490, 1395, 1397, 1505, and 1510 Wireless cards. This driver is included in the Ubuntu 8.10 release, and should be added to Ubuntu 8.04. It is currently only partially open-source, similar to ATI or NVIDIA video drivers, so keep this in mind when deciding if you want to use it. For those who want to try it out immediately, the driver can be downloaded from here.

We're currently offering the Dell 1397 card with the Studio 15 system with Ubuntu 8.04, and  the 1395 card is supported on our new Inspiron Mini 9. Please give us feedback on how well this driver works for you on any of our Dell wireless cards on our Linux Desktop mailing list.

---------------


Christopher Tozzi's blog을 읽어보면 Broadcom이 리눅스 데스크탑 시장에 대한 생각을 바꾸고 리눅스 드라이버를 내놓기 시작한다는 내용 같다. 그동안 Broadcom에서의 공식적인 리눅스 드라이버가 없어 b43 project가 구성 되었었다는 이야기도 있는거 같고...

http://www.broadcom.com/support/802.11/linux_sta.php

홈페이지에서 Dell Wireless 1505n Driver(Broadcom 4328 Chipset)를 받을 수 있는데 
확인한 결과 커널 2.6.27 이상 버전에서는 컴파일이 안되므로 약간의 수정이 필요하다.
iwe_stream_add_*() API가 변경되어서 해당 부분만 수정하면 된다. 다음은 diff git 기록...
(http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.27.y.git;a=commit;h=ccc580571cf0799d0460a085a7632b77753f083e)

그동안 ndiswrapper를 이용해야 Broadcom BCM4328 무선랜이 사용 가능했는데,
이제 그럴 필요가 없을 듯 ...

노트북 Dell M1330 XPS를 사용하는데 이 넘 무선랜이 하필 Broadcom이라.. 그 동안 고생 좀 했다는 거... 어제 리눅스에서 드라이버가 잡히는 거 까지 확인을 완료하고... (커널 버전 2.6.27.2에서)
공유기 문제로 인해 ping까지는 확인을 못해봤지만 동작은 제대로 되는거 같다.

테스트 환경 : Fedora Core 8, Linux Kernel 2.6.27.2

Posted by initproc
,
파이프라이닝 개관
 파이프라이닝은 여러 개의 명령어가 중첩해 실행되는 구현기술이다.
 파이프라이닝은 명령어 처리량을 증가시킴으로써 성능을 향상시킨다.


명령어 실행 단계
1. 명령어를 메모리부터 가져온다.
2. 명령어롤 해독하는 동시에 레지스터를 읽는다.
3. 연산을 수행하거나 주소를 계산한다.
4. 데이터 메모리에 있는 피연산자를 접근한다.
5. 결과값을 레지스터에 쓴다.


파이프라인 해저드
 구조적 해저드, 데이터 해저드, 제어 해저드

 구조적 해저드 - 같은 클럭 사이클에 실행하기를 원하는 명령어의 조합을 하드웨어가 지원할 수 없는 경우. 가령 메모리부터 명령어를 가져옴과 동시에 메모리로부터 데이터를 가져와야 하는 명령어를 수행해야 하는 경우 메모리가 하나만 있다면 도시에 메모리로부터 데이터를 가져 올 수 없기에 하드웨어의 구조적 문제에 직면한다.

 데이터 해저드 - 한 단계가 다른 단계가 끝나기를 기다리기 때문에 파이프라인이 지연되어야만 하는 경우 일어난다.  이는 한 명령어가 파이프라인 상에 있는 앞선 명령어에 종속성을 가질 때 데이터 해저드가 일어난다. 가령 add 명령어 뒤어 바로 sub 명령어가 있다면 add는 명령어 실행 단계 중에서 3,4,5를 수행한 이후에야 결과값을 레지스터에 쓴다. 그렇다면 3 단계의 파이프라인을 포기해야 함을 의미한다. 이런 경우 전방전달(forwarding 또는 bypassing)을 이용해 해결한다.

 제어 해저드 - 다른 명령어들이 실행중에 한 명령어의 결과값에 기반을 둔 결정을 할 필요가 있을때 발생한다. 즉 분기 명령어가 이에 해당한다.

지연분기 : 이는 분기 명령어 다음에 나오는 명령어는 분기조건이 참인지 거짓인지 상관없이 항상 실행된다는 것을 의미한다. 조건이 거짓이면 보통의 분기처럼 실행된다. 조건이 참이면 지연분기는 분기 명령어 바로 다음 명령어를 먼저 실행하고 명시된 분기목적지 주소로 건너뛴다.

분기예측 : 어떤 경우는 분기한다 혹은 분기하지 않는다고 가정하는 것이다. 각 분기가 일어났는지, 안 일어났는지 이력을 기록하고 미래를 예측하기 위해 최근의 과거 이력을 사용한다.

Posted by initproc
,