Visual Studio 2019 와 MSYS2 MinGW64 에서 테스트 된 소스입니다.

 혹시 MinGW 에서 컴파일되지 않으면

$ packman -S mpfr

명령으로 mpfr 라이브러리를 설치하고 컴파일하면 된다.

 

// Filename: calcGammaFn.c
//
// Compile: gcc -o calcGammaFn calcGammaFn.c -lmpfr -lgmp
// Execute: ./calcGammaFn
//     Or
// Compile: cl calcGammaFn.c /I. mpfr.lib
// Execute: calcGammaFn
//
// Date: 2021.01.28


#include <stdio.h>
#include <math.h>    // for log(10)
#include <mpfr.h>

int main()
{
  mpfr_t x; 
  int i, inex;

  mpfr_set_emin (-41);
  mpfr_init2 (x, 42);

  for (i = 1; i <= 17; i++)
  {
      mpfr_set_ui (x, i, MPFR_RNDN);
      inex = mpfr_gamma (x, x, MPFR_RNDZ);      
      mpfr_subnormalize (x, inex, MPFR_RNDZ);
      mpfr_dump (x);
  }

  printf("\n");

  for (i = 1; i <= 17; i++)
  {
      mpfr_set_ui (x, i, MPFR_RNDN);
      inex = mpfr_gamma (x, x, MPFR_RNDZ);
      mpfr_printf("Gamma(%2d) = %2d! = %Rf\n", i, i - 1, x);
  }

  printf("\n");

  for (i = 1; i <= 17; i++)
  {
      mpfr_set_ui (x, i, MPFR_RNDN);
      inex = mpfr_lngamma (x, x, MPFR_RNDZ);
      mpfr_printf("LogGamma(%2d) = Log(%2d!) = %Rf\n", i, i - 1, x);
  }

  printf("\n");

 double t10 = log(10.0);
 printf("log(10) = %f\n", t10);
 
  printf("\n");

  for (i = 1; i <= 17; i++)
  {
      mpfr_set_ui (x, i, MPFR_RNDN);
      inex = mpfr_lngamma (x, x, MPFR_RNDZ);      
      inex = mpfr_div_d(x, x, t10,  MPFR_RNDZ);
      mpfr_printf("Log10Gamma(%2d) = Log10(%2d!) = %Rf\n", i, i - 1, x);
  }

  mpfr_clear (x);
  
  return 0;
}

/*
Output:
LogGamma( 1) = Log( 0!) = 0
LogGamma( 2) = Log( 1!) = 0
LogGamma( 3) = Log( 2!) = 0.693147
LogGamma( 4) = Log( 3!) = 1.791759
LogGamma( 5) = Log( 4!) = 3.178054
LogGamma( 6) = Log( 5!) = 4.787492
LogGamma( 7) = Log( 6!) = 6.579251
LogGamma( 8) = Log( 7!) = 8.525161
LogGamma( 9) = Log( 8!) = 10.604603
LogGamma(10) = Log( 9!) = 12.801827
LogGamma(11) = Log(10!) = 15.104413
LogGamma(12) = Log(11!) = 17.502308
LogGamma(13) = Log(12!) = 19.987214
LogGamma(14) = Log(13!) = 22.552164
LogGamma(15) = Log(14!) = 25.191221
LogGamma(16) = Log(15!) = 27.899271
LogGamma(17) = Log(16!) = 30.671860

log(10) = 2.302585

Log10Gamma( 1) = Log10( 0!) = 0
Log10Gamma( 2) = Log10( 1!) = 0
Log10Gamma( 3) = Log10( 2!) = 0.301030
Log10Gamma( 4) = Log10( 3!) = 0.778151
Log10Gamma( 5) = Log10( 4!) = 1.380211
Log10Gamma( 6) = Log10( 5!) = 2.079181
Log10Gamma( 7) = Log10( 6!) = 2.857332
Log10Gamma( 8) = Log10( 7!) = 3.702431
Log10Gamma( 9) = Log10( 8!) = 4.605521
Log10Gamma(10) = Log10( 9!) = 5.559763
Log10Gamma(11) = Log10(10!) = 6.559763
Log10Gamma(12) = Log10(11!) = 7.601156
Log10Gamma(13) = Log10(12!) = 8.680337
Log10Gamma(14) = Log10(13!) = 9.794280
Log10Gamma(15) = Log10(14!) = 10.940408
Log10Gamma(16) = Log10(15!) = 12.116500
Log10Gamma(17) = Log10(16!) = 13.320620
*/

 

 

 

 

 

Posted by Scripter

댓글을 달아 주세요

Cygwin 에서는 printf 와 wprint 를 동시에 사용하는 경우, 컴파일은 성공하지만 실행하면 wprintf 가 제대로 동작하지 않는다.  그리고 wprint 나 swptinf 사용 시 스트링을 출력하기 위해서는 %s 대신 %ls 포맷을 사용해야 한다.

Cygwin 의 경우 wchar_t 의 크기는 2바이트이다.

 

#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>

int main(int argc, const char *argv[]) {
    wchar_t wt[100];

    /// setlocale(LC_ALL,"kr_KR.UTF-8");
    setlocale(LC_ALL,"");
    // printf("sizeof(wchar_t) = %d\n", sizeof(wchar_t));
    // printf("For more informations, \nsee: http://www.firstobject.com/wchar_t-string-on-linux-osx-windows.htm\n");

    wprintf(L"sizeof(wchar_t) = %d\n", sizeof(wchar_t));
    wprintf(L"For more informations, \nsee: http://www.firstobject.com/wchar_t-string-on-linux-osx-windows.htm\n");

    wprintf(L"\n");
    wcscpy(wt, L"abc 가나다");
    wprintf(L"%ls\n", wt);
    swprintf(wt, wcslen(L"abc 가나다") + 1, L"%ls", L"abc 가나다");
    wprintf(L"%ls\n", wt);
    wprintf(L"%ls\n", L"abc 가나다");
    wprintf(L"abc 가나다\n");

    return 0;
}

 

컴파일:

$ gcc -o testWcharT_02 testWcharT_02.c

실행:

$ ./testWchaTr_02

sizeof(wchar_t) = 2
For more informations,
see: http://www.firstobject.com/wchar_t-string-on-linux-osx-windows.htm

abc 가나다
abc 가나다
abc 가나다
abc 가나다

 

 

 

 

Posted by Scripter

댓글을 달아 주세요

우선 다음은 ms949 인코딩으로 저장한 C 소스이다.

* 소스 파일명: hello.c

#include <stdio.h>
#include <string.h>

int main()
{
    printf("Hello, 안녕하세요?\n");
    printf("strlen(\"Hello, 안녕하세요?\\n\") = %d\n", strlen("Hello, 안녕하세요?\n"));

 return 0;
}

* 컴파일

> gcc -o hello hello.c

*

 실행

> hello

Hello, 안녕하세요?
strlen("Hello, 안녕하세요?\n") = 19

 

다음은 utf-8 인코딩으로 저장한 C 소스이다.

* 소스 파일명: hello2.c

#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>

#define wstrlen wcslen

int main()
{
    setlocale(LC_ALL,"");

    printf("Using strlen():\n");
    printf("Hello, 안녕하세요?\n");
    printf("strlen(\"Hello, 안녕하세요?\\n\") = %d\n", strlen("Hello, 안녕하세요?\n"));

    wprintf(L"Using wcslen():\n");
 wprintf(L"Hello, 안녕하세요?\n");
    wprintf(L"wstrlen(\"Hello, 안녕하세요?\\n\") = %d\n", wstrlen(L"Hello, 안녕하세요?\n"));

 return 0;
}

* 컴파일

> gcc -o hello2 hello2.c

* 실행

> hello2

Using strlen():
Hello, ?덈뀞?섏꽭??
strlen("Hello, ?덈뀞?섏꽭??\n") = 24
Using wcslen():
Hello, 안녕하세요?
wstrlen("Hello, 안녕하세요?\n") = 14

 

다음도 utf-8 인코딩으로 저장한 C 소스이다.

* 소스 파일명: hello3.c

#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>

#define wstrlen wcslen

int main()
{
 char as[] = "Hello, 안녕하세요?";
 wchar_t bs[] = L"Hello, 안녕하세요?";

 setlocale(LC_ALL,"");

    printf("Using strlen():\n");
    printf("Hello, 안녕하세요?\n");
    printf("strlen(\"Hello, 안녕하세요?\\n\") = %d\n", strlen("Hello, 안녕하세요?\n"));
    printf("strlen(\"%s\") = %d\n", as, strlen(as));
    printf("\n");

    wprintf(L"Using wcslen():\n");
 wprintf(L"Hello, 안녕하세요?\n");
    wprintf(L"wstrlen(\"Hello, 안녕하세요?\\n\") = %d\n", wstrlen(L"Hello, 안녕하세요?\n"));
    wprintf(L"wstrlen(\"%s\") = %d\n", bs, wstrlen(bs));

 return 0;
}

* 컴파일

> gcc -o hello3 hello3.c

* 실행

> hello3

Using strlen():
Hello, ?덈뀞?섏꽭??
strlen("Hello, ?덈뀞?섏꽭??\n") = 24
strlen("Hello, ?덈뀞?섏꽭??") = 23

Using wcslen():
Hello, 안녕하세요?
wstrlen("Hello, 안녕하세요?\n") = 14
wstrlen("Hello, 안녕하세요?") = 13

 

 

Posted by Scripter

댓글을 달아 주세요

pdcurses 를 컴파일하여 Visual C++ 용 라이브러리 만들기

프롬프트> nmake -f vcwin32.mak

 

* 테스트용 소스 파일:  helloworld.c (http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/helloworld.html 에 있는 ncurses 용 소스에서 인클루드 문의 ncurses.h 를 curses.h 로 변경한 것 뿐임)

/*
 * Filename: helloworld.c
 *
 * Compile: cl /c helloworld.c /I .
 *       Link: link -nologo helloworld.obj pdcurses.lib user32.lib gdi32.lib advapi32.lib shell32.lib comdlg32.lib
*   Or
 * Compile & Link: cl helloworld.c -I . pdcurses.lib user32.lib gdi32.lib shell32.lib comdlg32.lib
 *
 * Execute: helloworld
 *
 * Date: 2014. 1. 15.
 */

#include <curses.h>           /* changed from <ncurses.h> */

int main()

    initscr();                          /* Start curses mode     */


    printw("Hello World !!!");    /* Print Hello World    */
    refresh();                         /* Print it on to the real screen */
    getch();                          /* Wait for user input */

    endwin();                        /* End curses mode    */

    return 0;
}

 

* 실행 결과:

 

 

 

Posted by Scripter

댓글을 달아 주세요

ncurses(또는 curses) 는 Linux/Unix 계열의 환경에서 VT100 등의 터미널과 호환되는 윈도우형 입출력 라이브러이다. 이를 이용하면 윈도우의 임의의 위치에 출력도 하고, 임의의 위치에서 입력을 받을 수도 있다.

* 카라슈바 곱셈 참조

다음은 Linux 나 Cygwin 환경이면 gcc 로 컴파일하여 실행되는 C 소스이다.

 

/*
 * Filename: ezmult_003.c
 *
 * Compile: gcc -o ezmult_003 ezmult_003.c -lform -lncurses
 *
 * Execute: ./ezmult_003
 *
 *    Date: 2014. 1. 6. (Mon)  v0.002
 *    Date: 2014. 1. 8. (Wed)  v0.003
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <form.h>
#include <ncurses.h>

int main()
{
    int x0, y0, z0;
    int s01, s02, t0;
    int x, y, z;
    int s1, s2, t;
    int i, j;
    int flag_insert_mode = 1;
    int o1 = 0;
    int o2 = 0;
    int o3 = 0;

    FIELD *field[4];
    FORM  *my_form;
    int ch;
 
    /* curses 초기화하기 */
    initscr();
    start_color();    // 색상을 사용하려면 initscr() 호출 후 즉시 이를 호출해야 함
    nonl();            // 필드에서 엔터 키가 작용되게 하기 위함
    cbreak();
    noecho();
    keypad(stdscr, TRUE);


    srand(time(NULL));
    x = rand()/(RAND_MAX + 1.0)*90 + 10;
    y = rand()/(RAND_MAX + 1.0)*90 + 10;
    z = x*y;
    s1 = (x/10)*(y/10);
    s2 = (x%10)*(y%10);
    t = (x/10)*(y%10) + (x%10)*(y/10);
   
    if (s1 < 10)
    {
         o1 = 1;
    }
    if (t < 100)
    {
         o2 = 1;
    }
    if (z < 1000)
    {
         o3 = 1;
    }
    refresh();
    

    /* 필드 초기화 */
    field[0] = new_field(1, 4-o1,  6, 14+o1, 0, 0);
    field[1] = new_field(1, 3-o2,  7, 14+o2, 0, 0);
    field[2] = new_field(1, 4-o3,  9, 14+o3, 0, 0);
    field[3] = NULL;


    /* 폼 생성하여 붙여 넣기 */
    my_form = new_form(field);
    post_form(my_form);
    refresh();


     /* 색상 초기화 */
    init_pair(1, COLOR_WHITE, COLOR_GREEN);
    init_pair(2, COLOR_WHITE, COLOR_GREEN);
    init_pair(3, COLOR_WHITE, COLOR_GREEN);
    init_pair(4, COLOR_MAGENTA, COLOR_BLACK);
    init_pair(5, COLOR_CYAN, COLOR_BLACK); 
    init_pair(6, COLOR_WHITE, COLOR_BLACK);
    init_pair(7, COLOR_BLACK, COLOR_WHITE);


    x0 = rand()/(RAND_MAX + 1.0)*90 + 10;
    y0 = rand()/(RAND_MAX + 1.0)*90 + 10;
    z0 = x0*y0;
    s01 = (x0/10)*(y0/10);
    s02 = (x0%10)*(y0%10);
    t0 = (x0/10)*(y0%10) + (x0%10)*(y0/10);


    mvprintw(3, 4, "%4d", x0);
    mvprintw(4, 3, "x%4d", y0);
    mvprintw(5, 3, "-----");
    mvprintw(6, 4, "%2d%02d", s01, s02);
    mvprintw(7, 4, "%3d", t0);
    mvprintw(8, 3, "-----");
    mvprintw(9, 4, "%4d", z0);
    refresh();


    mvprintw(3, 14, "%4d", x);
    mvprintw(4, 13, "x%4d", y);
    mvprintw(5, 13, "-----");
    mvprintw(8, 13, "-----");
    attron(COLOR_PAIR(7));
    mvprintw(0, 0, "Ins");
    attron(COLOR_PAIR(6));
    move(6, 14);
    refresh();


    set_field_type(field[0], TYPE_INTEGER, 0, 0, 9999);
    set_field_type(field[1], TYPE_INTEGER, 0, 0, 999);
    set_field_type(field[2], TYPE_INTEGER, 0, 0, 9999);
    field_opts_on(field[0], O_EDIT);
    field_opts_on(field[1], O_EDIT);
    field_opts_on(field[2], O_EDIT);
    field_opts_on(field[0], O_ACTIVE);
    field_opts_on(field[1], O_ACTIVE);
    field_opts_on(field[2], O_ACTIVE);

 
    /* 필드 옵션 설정 */
    set_field_back(field[0], A_UNDERLINE); 
    set_field_back(field[1], A_UNDERLINE); 

    set_field_back(field[2], A_UNDERLINE); 


    /* 필드 옵션 설정 */
    set_field_fore(field[0], COLOR_PAIR(1));
    set_field_back(field[0], COLOR_PAIR(2));
    set_field_fore(field[1], COLOR_PAIR(1));

    set_field_back(field[1], COLOR_PAIR(2));
    set_field_fore(field[2], COLOR_PAIR(1));
    set_field_back(field[2], COLOR_PAIR(2));


    if (s1 >= 10)
        move(6, 14);
    else
        move(6, 15);
    refresh();


    /* 사용자 요구에 따라 번복 여부 결정 */
    while((ch = getch()) != KEY_F(1) && ch != 0x1B && ch != 0x0D)   
        switch(ch)
      {

           case KEY_DOWN:
           case KEY_ENTER:
               /* 다음 필드로 가기 */
               form_driver(my_form, REQ_NEXT_FIELD);
               break;
          case KEY_UP:
              /* 이전 필드로 가기 */
              form_driver(my_form, REQ_PREV_FIELD);
              break;
         case KEY_BACKSPACE:
         case 0x7F:
              form_driver(my_form, REQ_DEL_PREV);
              break;
         case KEY_IC:
              if (flag_insert_mode != 0)
             {
                 form_driver(my_form, REQ_OVL_MODE);
                 getyx(stdscr, j, i);
                 mvprintw(0, 0, "   ");
                 move(j, i);
                 flag_insert_mode = 0;
             }
             else
            {
                 form_driver(my_form, REQ_INS_MODE);
                 getyx(stdscr, j, i);
                attron(COLOR_PAIR(7));
                mvprintw(0, 0, "Ins");
                attron(COLOR_PAIR(6));
                move(j, i);
                flag_insert_mode = 1;
            }
            break;
        case KEY_DC:
            form_driver(my_form, REQ_DEL_CHAR);
            break;
        case KEY_LEFT:
            form_driver(my_form, REQ_LEFT_CHAR);
            break;
        case KEY_RIGHT:
            form_driver(my_form, REQ_RIGHT_CHAR);
            break;
        default:
            form_driver(my_form, ch);
            break;
       }
    }
 
    form_driver(my_form, REQ_NEXT_FIELD);
 
    attron(COLOR_PAIR(6));
    mvprintw(13, 0, "You have answered");
    if (atoi(field_buffer(field[0], 0)) == s1*100 + s2)
         attron(COLOR_PAIR(5));
    else
         attron(COLOR_PAIR(4));
    mvprintw(14, 8, "%4d", atoi(field_buffer(field[0], 0)));
    if (atoi(field_buffer(field[1], 0)) == t)
         attron(COLOR_PAIR(5));
    else
         attron(COLOR_PAIR(4));
    mvprintw(15, 8, "%3d", atoi(field_buffer(field[1], 0)));
    if (atoi(field_buffer(field[2], 0)) == z)
         attron(COLOR_PAIR(5));
    else
         attron(COLOR_PAIR(4));
    mvprintw(16, 8, "%4d", atoi(field_buffer(field[2], 0)));

    attron(COLOR_PAIR(6));
    mvprintw(13, 20, "Right answer is");
    mvprintw(14, 28, "%2d%02d", s1, s2);
    mvprintw(15, 28, "%3d", t);
    mvprintw(16, 28, "%4d", z);
    if (atoi(field_buffer(field[0], 0)) == s1*100 + s2
         && atoi(field_buffer(field[1], 0)) == t
         && atoi(field_buffer(field[2], 0)) == z)
        mvprintw(18, 0, "    Your answer is right.");
    else
        mvprintw(18, 0, "    Your answer is wrong.");
    mvprintw(21, 0, "Press any key to quit...");
    getch();
   
    /* 폼을 떼어내고 메모리를 해제한다. */
    unpost_form(my_form);
    free_form(my_form);
    free_field(field[0]);
    free_field(field[1]);
    free_field(field[2]);

    endwin();

    return 0;
}
 

 

* 실행 결과:

 


 

Posted by Scripter

댓글을 달아 주세요

32bit OS 에서는 int 타입과 long 타입이 다 같이 4바이트의 크기를 갖지만.

64bit OS 에서는 int 타입이 4바이트, long 타입이 8바이트의 크기를 갖는다.

그렇다면 64비트 리눅스 환경에서 32비트 용으로 작성된 C 소스를 gcc 로 컴파일하려면 어떻게 해야 할까? 

 

// Filename: testIntSize.c

int main()
{
#include <stdio.h>

int main()
{
    printf("sizeof(int) = %d\n", sizeof(int));
    printf("sizeof(long) = %d\n", sizeof(long));

    return 0;
}

 

# 64비트 용으로 컴파일하고 실행하기

$ gcc -o testIntSize testIntSize.c

$ ./testIntSize

sizeof(int) = 4
sizeof(long) = 8

 

# 32비트 용으로 컴파일하고 실행하기 (옵션 -m32 추가)

$ gcc -m32 -o testIntSize testIntSize.c

$ ./testIntSize

sizeof(int) = 4
sizeof(long) = 4

 

 

Posted by Scripter

댓글을 달아 주세요

 

Visual C++ 2010 으로 컴파일할 경우, 헤더파일 inttypes.h 가 Visual C++ 2010 에는 빠져 있으므로 http://msinttypes.googlecode.com/svn/trunk/inttypes.h 를 가져와서 아래의 소스와 동일한 디렉토리에 두고 컴파일한다.

char * 타입의 C 스트링으로 부터 long long 타입의 정수로 파싱하려면 C99 에서 정한 함수 strtoll 함수를 쓰면 되는데 이 함수 역시 Visual C++ 2010 에는 빠져 있으므로, _strtoi64 함수로 대체하기 위해 소스의 앞 부분에 매크로 정의 #define strtoll _strtoi64 를 추가하였다.

또 main 함수 안에서 사용된 llabs 함수는 long long 타입의 정수의 절댓값을 구하는 함수이다. abs 함수를 쓰면 절댓값이 int 타입의 값으로 나오므로 long long 타입에 대하여는 잘못된 절댓값을 가져올 수 있다.

 

* gcc 4.6.* 또는 Visual Studio 2010 의 cl 로 컴파일되는 C 소스

/*
 * Filename: eulerPhiGoodC_01.c
 *
 *  Purpose:
 *          Calculate the Euler phi function of a given nonzero integer
 *          with using its muliplicative property.
 *
 *          The Euler phi function of a given positive integer n is defined as.
 *          the number of positive integers which are relative prime to n
 *          from 1 to n.
 *
 * Compile: gcc -o eulerPhiGoodC_01 eulerPhiGoodC_01.c
 *    Or
 * Compile: cl /DVC2010 eulerPhiGoodC_01.c
 *
 * Execute: ./eulerPhiGoodC_01 [nnn]
 *    Or
 * Execute: eulerPhiGoodC_01 [nnn]
 *
 *  Date: 2011. 11.  7 (Mon)    eulerPhiGoodPython_01.py
 *  Date: 2013. 12. 13 (Fri)    eulerPhiGoodC_01.c
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#ifdef VC2010
  #include "inttypes.h"
  #define strtoll _strtoi64
#else
  #include <inttypes.h>
#endif
 
void printUsage()
{
    printf("Usage: eulerPhiGoodC_01 [nnnnnn]\n");
    printf("nnnnnn should be an integer.\n");
}

long long gcd(long long a, long long b)
{
    long long a1 = abs(a);
    long long b1 = abs(b);
    long long q = a1;
    long long r = b1;
    long long t;
    while (r != 0)
    {
        t = r;
        r = q % r;
        q = t;
    }
    return q;
}

int divide_each(long long n)
{
    long long a = 3;

    if ((n & 0x1) == 0 || n <= 1)
        return 0;
    else if (n == 2)
        return 1;

    while (a*a <= n)
    {
        if ((n % a) == 0)
            return 0;
        a += 2;
    }
    
    return 1;
}

int is_prime(long long n)
{
    return divide_each(n);
}

long long next_prime(long long n)
{
    long long k = llabs(n);
   
    k = k + 1;
    if (k <= 2)
    {
        return 2LL;
    }

    if ((k % 2) == 0 && k > 2)
        k += 1;
    while (!is_prime(k))
        k += 2;

    return k;
}


 

int main(int argc, const char *argv[])
{
    long long n = 0;
    long long cnt = 0;
    long long nphi = 0;
    long long sum = 0;
    long long t = 0;
    long long g = 1;
    long long m = 0;
    long long p = 1;
    long long *factors = (long long *)malloc(sizeof(long long)*200);
    long long nfactor = 0;
    long long ndivisor = 1;   // the number of positive divisors of the input integer
    long long nsum = 1;       // the sum of all positive divisors of the input integer
    int ndx = 0;        // index of storing position factor in factors
    long long *divisors = NULL;
    long long last_prime;
    int i, j, k;

    if (argc != 2)
    {
        printUsage();
        exit(1);
    }
    else
    {
        n = strtoll(argv[1], NULL, 10);
        n = llabs(n);
        if (n != 0)
        {
            t = n;
            k = 0;
            m = 0;  // multiplicity of prime factor
            ndivisor = 1;   // the number of positive divisors of the input integer
            nsum = 1;       // the sum of all positive divisors of the input integer
            nphi = 1;       // the numner of positive integers relative prime to the input integer
    
            p = 1;
            while (t > 1 && p*p <= n)
            {
                p = next_prime(p);
                m = 0;
                while (t % p == 0)
                {
                    t = (long long)(t / p);
                    m = m + 1;
                }

                if (m > 0)
                {
                    factors[ndx] = p;
                    ndx += 1;
                    factors[ndx] = m;
                    ndx += 1;
                    nfactor += 1;
                    ndivisor *= (m + 1);
                    nsum *= (long long)((pow(p, m+1) - 1)/(p - 1));
                    nphi *= (long long)(pow(p, m - 1)*(p - 1));
                }
            }
    

            if (is_prime(t))
            {
                m = 1;
                factors[ndx] = t;
                ndx += 1;
                factors[ndx] = m;
                ndx += 1;
                nfactor += 1;
                ndivisor *= (m + 1);
                nsum *= (long long)((pow(t, m+1) - 1)/(t - 1));
                nphi *= (long long)pow(t, m - 1)*(t - 1);
                m = 0;
            }
                
            printf("Prime factorization: %"PRId64" = ", n);
            for (i = 0 ; i < 2*nfactor; i += 2)
            {
                printf("%"PRId64"^{%"PRId64"} ", factors[i], factors[i + 1]);
            }
            printf("\n");
            printf("The number of positive divisors:  tau(%"PRId64") =  %"PRId64".\n", n, ndivisor);
            printf("The sum of all positive divisors:  sigma(%"PRId64") = %"PRId64".\n", n, nsum);
            printf("The number of positive integers relatively prime:  phi(%"PRId64") = %"PRId64"\n", n, nphi);
            if (nsum == n + 1)
                printf("The integer %"PRId64" is a prime number.\n", n);
            else
                printf("The integer %"PRId64" is not a prime number.\n", n);

            divisors = (long long *)malloc(sizeof(long long)*ndivisor);

            cnt = 0;
            ndx = 0;
            divisors[ndx] = 1;
            ndx += 1;
            cnt = 1;
            for (i = 0; i < 2*nfactor; i += 2)
            {
                p = factors[i];
                m = factors[i + 1];
                for (k = 1; k <= m; k++)
                {
                    for (j = 0; j < cnt; j++)
                    {
                        divisors[ndx] = divisors[j]*pow(p, k);
                        ndx += 1;
                    }
                }
                cnt = ndx;
            }
            printf("The positive divisors of %"PRId64" are\n", n);
            for (i = 0; i < ndivisor - 1; i++)
            {
                printf("%"PRId64", ", divisors[i]);
            }
            printf("%"PRId64".\n", divisors[ndivisor - 1]);
        }
    }
 
    free(factors);
    free(divisors);
 
    return 0;
}

 

 

실행> eulerPhiGoodC_01 240
Prime factorization: 240 = 2^{4} 3^{1} 5^{1}
The number of positive divisors:  tau(240) =  20.
The sum of all positive divisors:  sigma(240) = 744.
The number of positive integers relatively prime:  phi(240) = 64
The integer 240 is not a prime number.
The positive divisors of 240 are
1, 2, 4, 8, 16, 3, 6, 12, 24, 48, 5, 10, 20, 40, 80, 15, 30, 60, 120, 240.

실행> eulerPhiGoodC_01 24345
Prime factorization: 24345 = 3^{2} 5^{1} 541^{1}
Prime factorization: 24345 = 3^{2} 5^{1} 541^{1}
The number of positive divisors:  tau(24345) =  12.
The sum of all positive divisors:  sigma(24345) = 42276.
The number of positive integers relatively prime:  phi(24345) = 12960
The integer 24345 is not a prime number.
The positive divisors of 24345 are
1, 3, 9, 5, 15, 45, 541, 1623, 4869, 2705, 8115, 24345.

실행> eulerPhiGoodC_01 2434500
Prime factorization: 2434500 = 2^{2} 3^{2} 5^{3} 541^{1}
The number of positive divisors:  tau(2434500) =  72.
The sum of all positive divisors:  sigma(2434500) = 7694232.
The number of positive integers relatively prime:  phi(2434500) = 648000
The integer 2434500 is not a prime number.
The positive divisors of 2434500 are
1, 2, 4, 3, 6, 12, 9, 18, 36, 5, 10, 20, 15, 30, 60, 45, 90, 180, 25, 50, 100, 7
5, 150, 300, 225, 450, 900, 125, 250, 500, 375, 750, 1500, 1125, 2250, 4500, 541
, 1082, 2164, 1623, 3246, 6492, 4869, 9738, 19476, 2705, 5410, 10820, 8115, 1623
0, 32460, 24345, 48690, 97380, 13525, 27050, 54100, 40575, 81150, 162300, 121725
, 243450, 486900, 67625, 135250, 270500, 202875, 405750, 811500, 608625, 1217250
, 2434500.

실행> eulerPhiGoodC_01 481000000008
Prime factorization: 481000000008 = 2^{3} 3^{1} 11^{1} 73^{1} 24958489^{1}
The number of positive divisors:  tau(481000000008) =  64.
The sum of all positive divisors:  sigma(481000000008) = 1329788347200.
The number of positive integers relatively prime:  phi(481000000008) = 143760890
880
The integer 481000000008 is not a prime number.
The positive divisors of 481000000008 are
1, 2, 4, 8, 3, 6, 12, 24, 11, 22, 44, 88, 33, 66, 132, 264, 73, 146, 292, 584, 2
19, 438, 876, 1752, 803, 1606, 3212, 6424, 2409, 4818, 9636, 19272, 24958489, 49
916978, 99833956, 199667912, 74875467, 149750934, 299501868, 599003736, 27454337
9, 549086758, 1098173516, 2196347032, 823630137, 1647260274, 3294520548, 6589041
096, 1821969697, 3643939394, 7287878788, 14575757576, 5465909091, 10931818182, 2
1863636364, 43727272728, 20041666667, 40083333334, 80166666668, 160333333336, 60
125000001, 120250000002, 240500000004, 481000000008.

실행> eulerPhiGoodC_01 481000000009
Prime factorization: 481000000009 = 83^{1} 347^{1} 3361^{1} 4969^{1}
The number of positive divisors:  tau(481000000009) =  16.
The sum of all positive divisors:  sigma(481000000009) = 488441580480.
The number of positive integers relatively prime:  phi(481000000009) = 473599042
560
The integer 481000000009 is not a prime number.
The positive divisors of 481000000009 are
1, 83, 347, 28801, 3361, 278963, 1166267, 96800161, 4969, 412427, 1724243, 14311
2169, 16700809, 1386167147, 5795180723, 481000000009.

실행> eulerPhiGoodC_01 481000000001
Prime factorization: 481000000001 = 367^{1} 1310626703^{1}
The number of positive divisors:  tau(481000000001) =  4.
The sum of all positive divisors:  sigma(481000000001) = 482310627072.
The number of positive integers relatively prime:  phi(481000000001) = 479689372
932
The integer 481000000001 is not a prime number.
The positive divisors of 481000000001 are
1, 367, 1310626703, 481000000001.

 

 

 

Posted by Scripter

댓글을 달아 주세요

우선 다음 소스는 컴파일하는데는 아무 문제가 없지만 실행 결과는 전혀 엉뚱하다.

printf 함수에 사용된 %lld 포맷에 문제가 있기 때문이다.

 

/*
 * Filename: testLongLong0.c
 *
 * Compile: gcc -o testLongLong0 testLongLong0.c
 *   or
 * Compile: cl testLongLong0.c
 */

#include <stdio.h>

int main()
{
    printf("Maximum long long value is %40lld\n", 9223372036854775807LL);
    printf("Maximum long long value is %40llu\n", 9223372036854775807ULL);
    printf("Maximum long long value is %40lld\n", 9223372036854775808LL);
    printf("Maximum long long value is %40llu\n", 9223372036854775808ULL);

    return 0;
}

 

우선 다음은 32비트 윈도우 XP의 명령창에서 Visual C++ 2010 의 명령줄 컴파일러 cl 로 컴파일하여 실행한 경우이다.

컴파일> cl testLongLong0.c
Microsoft (R) 32비트 C/C++ 최적화 컴파일러 버전 16.00.40219.01(80x86)
Copyright (c) Microsoft Corporation. 모든 권리 보유.

testLongLong0.c
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:testLongLong0.exe
testLongLong0.obj

실행> testLongLong0
Maximum long long value is                      9223372036854775807
Maximum long long value is                      9223372036854775807
Maximum long long value is                     -9223372036854775808
Maximum long long value is                      9223372036854775808

 

 

그리고 다읍은 32비트 윈도우 XP의 명령창에서 MinGW 의 gcc(버잔 4.7.3) 로 컴파일하여 실행한 경우이다.

컴파일> gcc -o testLongLong0 testLongLong0.c
testLongLong0.c: In function 'main':
testLongLong0.c:15:51: warning: integer constant is so large that it is unsigned
 [enabled by default]
testLongLong0.c:15:5: warning: this decimal constant is unsigned only in ISO C90
 [enabled by default]

실행> testLongLong0
Maximum long long value is                                       -1
Maximum long long value is                               4294967295
Maximum long long value is                                        0
Maximum long long value is                                        0

 

 

* ISO C99 표준에 따라 64비트 정수를 printf 함수로 출력할 때 inttypes.h 헤터파일을 인클루드하고 PRId64, PRIu64, PRIx64, PRIX64 등을 사용한다. 예를 들면,

        printf("My value is %10"PRId64"\n", some_64_bit_expression);

이다. scanf 함수로 64비트 정수를 입력받을 때는 SCNd64, SCNu64, SCNx64, SCNX64 등을 사용한다.

아래의 소스는 gcc 로 컴파일할 때 경고는 있지만 실행시 출력은 정상이다. 

/*
 * Filename: testLongLong1.c
 *
 * Compile: gcc -o testLongLong1 testLongLong1.c
 *
 * See: http://en.wikipedia.org/wiki/Printf_format_string
 * See: http://msinttypes.googlecode.com/svn/trunk/inttypes.h
 * See: http://en.wikibooks.org/wiki/C_Programming/C_Reference/inttypes.h
 */

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main()
{
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775807L);
    printf("       uint64 value is %40" PRIu64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIx64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIX64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 18446744073709551615ULL);

    printf("Maximum int64 value is |%-40" PRId64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIu64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIx64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIX64 "|\n", INT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIx64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIX64 "|\n", UINT64_MAX);

    return 0;
}

/*
-----------------
  Execute Result:
-----------------
Maximum int64 value is                      9223372036854775807
Maximum int64 value is                         7fffffffffffffff
Maximum int64 value is                         7FFFFFFFFFFFFFFF
       uint64 value is                      9223372036854775807
Maximum int64 value is                     -9223372036854775808
Maximum int64 value is                         8000000000000000
Maximum int64 value is                         8000000000000000
Maximum uint64 value is                      9223372036854775808
Maximum uint64 value is                         ffffffffffffffff
Maximum uint64 value is                         FFFFFFFFFFFFFFFF
Maximum uint64 value is                     18446744073709551615
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |7fffffffffffffff                        |
Maximum int64 value is |7FFFFFFFFFFFFFFF                        |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |ffffffffffffffff                        |
Maximum uint64 value is |FFFFFFFFFFFFFFFF                        |
*/

 

 

* Visual C++ 2010 에서는 64비트 정수를 printf 함수로 출력하기 위해 PRId64, PRIu64, PRIx64, PRIX64 등을 사용하면 inttypes.h 헤더 파일을 찾을 수 없다는 에러가 난다. 이 에러를 해결하기 위해 http://msinttypes.googlecode.com/svn/trunk/inttypes.h 를 인클루드하였다.

아래의 소스는 cl 로 경고 없이 컴파일도 잘 되고 실행시 출력도 정상이다. 

/*
 * Filename: testLongLong.c
 *
 * Compile: cl testLongLong.c
 *
 * See: http://en.wikipedia.org/wiki/Printf_format_string
 * See: http://msinttypes.googlecode.com/svn/trunk/inttypes.h
 * See: http://en.wikibooks.org/wiki/C_Programming/C_Reference/inttypes.h
 */

#include <stdio.h>
#include <stdio.h>
#include "inttypes.h"

int main()
{
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775807L);
    printf("       uint64 value is %40" PRIu64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIx64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIX64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 18446744073709551615ULL);

    printf("Maximum int64 value is |%-40" PRId64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIu64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIx64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIX64 "|\n", INT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIx64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIX64 "|\n", UINT64_MAX);

    return 0;
}

/*
-----------------
  Execute Result:
-----------------
Maximum int64 value is                      9223372036854775807
Maximum int64 value is                         7fffffffffffffff
Maximum int64 value is                         7FFFFFFFFFFFFFFF
       uint64 value is                      9223372036854775807
Maximum int64 value is                     -9223372036854775808
Maximum int64 value is                         8000000000000000
Maximum int64 value is                         8000000000000000
Maximum uint64 value is                      9223372036854775808
Maximum uint64 value is                         ffffffffffffffff
Maximum uint64 value is                         FFFFFFFFFFFFFFFF
Maximum uint64 value is                     18446744073709551615
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |7fffffffffffffff                        |
Maximum int64 value is |7FFFFFFFFFFFFFFF                        |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |ffffffffffffffff                        |
Maximum uint64 value is |FFFFFFFFFFFFFFFF                        |
*/

 

 

* 다음 소스는 gcc 또는 cl  어느 것으로도 컴파일되고 실행결과도 같지만, gcc 로 컴파일 할 때는 인크루드 부분을

        #include <inttypes.h>

로 수정해야 한다. gcc 는 4.7.x 이상이면 컴파일되고, Visual C++ 는 2008 이상이면 컴파일된다.

그대신 Visual C++ 2008 에는 헤더파일 stdint.h 가 빠져 있으므로 http://msinttypes.googlecode.com/svn/trunk/stdint.h  에서 내려받으면 된다. Visual C++ 2010 에는 이 헤더파일이 이미 있으므로 상관 없다.

 

* gcc 로 컴파일하기:

    gcc -std=c99 -o testLongLong2 testLong2.c

또는

    gcc -o testLongLong2 testLong2.c

* cl 로 컴파일하기:

    cl testLong2.c

 

/*
 * Filename: testLongLong2.c
 *
 * Compile: gcc -o testLongLong2 testLongLong2.c
 *     or
 * Compile:cl testLongLong2.c
 *
 * See: http://en.wikipedia.org/wiki/Printf_format_string
 * See: http://msinttypes.googlecode.com/svn/trunk/inttypes.h
 * See: http://msinttypes.googlecode.com/svn/trunk/stdint.h
 * See: http://en.wikibooks.org/wiki/C_Programming/C_Reference/inttypes.h
 */

#include <stdio.h>
#include "stdint.h"      //  #include <inttypes.h>  for gcc or Visual C++ 2010
#include "inttypes.h"    //  #include <inttypes.h>  for gcc

int main()
{
    printf(" INT64_MAX = %30" PRId64 "\n", INT64_MAX);
    printf(" INT64_MAX = %30" PRIx64 "\n", INT64_MAX);
    printf("UINT64_MAX = %30" PRIu64 "\n", UINT64_MAX);
    printf("UINT64_MAX = %30" PRIx64 "\n", UINT64_MAX);
    printf("\n");

    printf("Maximum  int64 value is %40" PRId64 "\n", 9223372036854775807LL);
    printf("Maximum  int64 value is %40" PRIx64 "\n", 9223372036854775807LL);
    printf("Maximum  int64 value is %40" PRIX64 "\n", 9223372036854775807LL);
    printf("        uint64 value is %40" PRIu64 "\n", 9223372036854775807LL);
    printf("Maximum  int64 value is %40" PRId64 "\n", 9223372036854775808ULL);
    printf("Maximum  int64 value is %40" PRIx64 "\n", 9223372036854775808ULL);
    printf("Maximum  int64 value is %40" PRIX64 "\n", 9223372036854775808ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 9223372036854775808ULL);
    printf("Maximum uint64 value is %40" PRIx64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIX64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 18446744073709551615ULL);

    printf("Maximum  int64 value is |%-40" PRId64 "|\n", INT64_MAX);
    printf("Maximum  int64 value is |%-40" PRIu64 "|\n", INT64_MAX);
    printf("Maximum  int64 value is |%-40" PRIx64 "|\n", INT64_MAX);
    printf("Maximum  int64 value is |%-40" PRIX64 "|\n", INT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIx64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIX64 "|\n", UINT64_MAX);

    return 0;
}

/*
-----------------
  Execute Result:
-----------------
 INT64_MAX =            9223372036854775807
 INT64_MAX =               7fffffffffffffff
UINT64_MAX =           18446744073709551615
UINT64_MAX =               ffffffffffffffff

Maximum  int64 value is                      9223372036854775807
Maximum  int64 value is                         7fffffffffffffff
Maximum  int64 value is                         7FFFFFFFFFFFFFFF
        uint64 value is                      9223372036854775807
Maximum  int64 value is                     -9223372036854775808
Maximum  int64 value is                         8000000000000000
Maximum  int64 value is                         8000000000000000
Maximum uint64 value is                      9223372036854775808
Maximum uint64 value is                         ffffffffffffffff
Maximum uint64 value is                         FFFFFFFFFFFFFFFF
Maximum uint64 value is                     18446744073709551615
Maximum  int64 value is |9223372036854775807                     |
Maximum  int64 value is |9223372036854775807                     |
Maximum  int64 value is |7fffffffffffffff                        |
Maximum  int64 value is |7FFFFFFFFFFFFFFF                        |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |ffffffffffffffff                        |
Maximum uint64 value is |FFFFFFFFFFFFFFFF                        |
*/

 

 

 

 

Posted by Scripter

댓글을 달아 주세요

C 언어 프로그래밍에서 까다로운 부분 중의 하나는 획득했던(할당받았던) 메모리를 여하히 해제하느냐이다. 프로그램밍의 사소한 오류로 메모리 부족 현상이 쉽게 일어나기 때문이다.

자바 언어, 파이썬 언어, C# 언어 등은 자동으로 쓰레기 수집(garbage collection)이 이루어지므로 거의 신경쓰지 않아도 되지만, C 언어는 소스 작성하는 프로그래머가 직접해야 한다.

오래 전(10여년 전)에 Hans Boehm 가 만들었던 C/C++ 언어용 쓰레기 수집기(Boehm-Demers-Weiser conservative garbage collector, 줄여사 BoehmGC 러고 부름)를 이용하여 컴파일되고 실행되는 소스이다. 이 쓰레기 수집기를 쓰면, 메모리 해제(free)를 프로그래머가 신경쓰지 않아도 된다. 그렇게 하기 위해서는 헤더 파일 추가 구문

              #include "gc.h"     또는      #include "gc/gc.h"

가 있어야 하고,  함수 malloc(크기) 대신에 매크로 GC_MALLOC(크기) 를, 함수 realloc(포인터, 크기) 대신에 매크로 GC_REALLOC(포인터, 크기) 를 사용해야 한다. 좀 더 좋은 성능을 위해서는 GC_MALLOC_ATOMIC(크기) 과 GC_enable_incremental() 을 사용하기도 한다. GC_MALLOC_ATOMIC 은 포인터를 전혀 갖지 않은 객체에 대하여만 적용된다. 



MinGW 의 gcc 나 Visual C++ 2010 용으로 동작하는지는 아직 확인 되지는 않았으나, Cygwin에는 Hans Boehm 의 쓰레기 수집기가 이미 설치되어 있어서, Cygwin 의  gcc 4.5.3 으로 컴파일할 수 있었다.

 

/*
 * Filename: testGC_01.c 
 *
 *           Test a garbage collection for C language.
 *
 * Compile: gcc -o testGC_01 testGC_01.c -lgc
 *
 * Execute: ./testGC_01
 *
 * See: http://www.hpl.hp.com/personal/Hans_Boehm/gc/simple_example.html
 */


#include "gc.h"
#include <assert.h>
#include <stdio.h>

int main()
{
    int i;

    GC_INIT(); /* Optional on Linux/X86; see below.  */
    for (i = 0; i < 10000000; ++i)
    {
        int **p = (int **) GC_MALLOC(sizeof(int *));
        int *q = (int *) GC_MALLOC_ATOMIC(sizeof(int));
        assert(*p == 0);
        *p = (int *) GC_REALLOC(q, 2 * sizeof(int));
        if (i % 100000 == 0)
            printf("Heap size = %d\n", GC_get_heap_size());
    }

    return 0;
}

 

 

실행 결과:
Heap size = 65536
Heap size = 131072
.................
.................
.................

 

 

* 단일 쓰레드에서 쓰레기 수집  벤치마크 테스트 (파일명: GCBench.c)

// This is adapted from a benchmark written by John Ellis and Pete Kovac
// of Post Communications.
// It was modified by Hans Boehm of Silicon Graphics.
// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
// Translated to C 15 March 2000 by Hans Boehm, now at HP Labs.
//
//      This is no substitute for real applications.  No actual application
//      is likely to behave in exactly this way.  However, this benchmark was
//      designed to be more representative of real applications than other
//      Java GC benchmarks of which we are aware.
//      It attempts to model those properties of allocation requests that
//      are important to current GC techniques.
//      It is designed to be used either to obtain a single overall performance
//      number, or to give a more detailed estimate of how collector
//      performance varies with object lifetimes.  It prints the time
//      required to allocate and collect balanced binary trees of various
//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
//      allocates roughly the same amount of memory.
//      Two data structures are kept around during the entire process, so
//      that the measured performance is representative of applications
//      that maintain some live in-memory data.  One of these is a tree
//      containing many pointers.  The other is a large array containing
//      double precision floating point numbers.  Both should be of comparable
//      size.
//
//      The results are only really meaningful together with a specification
//      of how much memory was used.  It is possible to trade memory for
//      better time performance.  This benchmark should be run in a 32 MB
//      heap, though we don't currently know how to enforce that uniformly.
//
//      Unlike the original Ellis and Kovac benchmark, we do not attempt
//      measure pause times.  This facility should eventually be added back
//      in.  There are several reasons for omitting it for now.  The original
//      implementation depended on assumptions about the thread scheduler
//      that don't hold uniformly.  The results really measure both the
//      scheduler and GC.  Pause time measurements tend to not fit well with
//      current benchmark suites.  As far as we know, none of the current
//      commercial Java implementations seriously attempt to minimize GC pause
//      times.

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

#ifdef GC
#  include "gc.h"
#endif

#ifdef PROFIL
  extern void init_profiling();
  extern dump_profile();
#endif

//  These macros were a quick hack for the Macintosh.
//
//  #define currentTime() clock()
//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)

#define currentTime() stats_rtclock()
#define elapsedTime(x) (x)

/* Get the current time in milliseconds */

unsigned
stats_rtclock( void )
{
  struct timeval t;
  struct timezone tz;

  if (gettimeofday( &t, &tz ) == -1)
    return 0;
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
}

static const int kStretchTreeDepth    = 18;      // about 16Mb
static const int kLongLivedTreeDepth  = 16;  // about 4Mb
static const int kArraySize  = 500000;  // about 4Mb
static const int kMinTreeDepth = 4;
static const int kMaxTreeDepth = 16;

typedef struct Node0_struct {
        struct Node0_struct * left;
        struct Node0_struct * right;
        int i, j;
} Node0;

#ifdef HOLES
#   define HOLE() GC_NEW(Node0);
#else
#   define HOLE()
#endif

typedef Node0 *Node;

void init_Node(Node me, Node l, Node r) {
    me -> left = l;
    me -> right = r;
}

#ifndef GC
  void destroy_Node(Node me) {
    if (me -> left) {
 destroy_Node(me -> left);
    }
    if (me -> right) {
 destroy_Node(me -> right);
    }
    free(me);
  }
#endif

// Nodes used by a tree of a given size
static int TreeSize(int i) {
        return ((1 << (i + 1)) - 1);
}

// Number of iterations to use for a given tree depth
static int NumIters(int i) {
        return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
}

// Build tree top down, assigning to older objects.
static void Populate(int iDepth, Node thisNode) {
        if (iDepth<=0) {
                return;
        } else {
                iDepth--;
#  ifdef GC
                  thisNode->left  = GC_NEW(Node0); HOLE();
                  thisNode->right = GC_NEW(Node0); HOLE();
#  else
                  thisNode->left  = calloc(1, sizeof(Node0));
                  thisNode->right = calloc(1, sizeof(Node0));
#  endif
                Populate (iDepth, thisNode->left);
                Populate (iDepth, thisNode->right);
        }
}

// Build tree bottom-up
static Node MakeTree(int iDepth) {
 Node result;
        if (iDepth<=0) {
#     ifndef GC
  result = calloc(1, sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     /* result is implicitly initialized in both cases. */
     return result;
        } else {
     Node left = MakeTree(iDepth-1);
     Node right = MakeTree(iDepth-1);
#     ifndef GC
  result = malloc(sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     init_Node(result, left, right);
     return result;
        }
}

static void PrintDiagnostics() {
#if 0
        long lFreeMemory = Runtime.getRuntime().freeMemory();
        long lTotalMemory = Runtime.getRuntime().totalMemory();

        System.out.print(" Total memory available="
                         + lTotalMemory + " bytes");
        System.out.println("  Free memory=" + lFreeMemory + " bytes");
#endif
}

static void TimeConstruction(int depth) {
        long    tStart, tFinish;
        int     iNumIters = NumIters(depth);
        Node    tempTree;
 int  i;

 printf("Creating %d trees of depth %d\n", iNumIters, depth);
       
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
#  ifndef GC
                  tempTree = calloc(1, sizeof(Node0));
#  else
                  tempTree = GC_NEW(Node0);
#  endif
                Populate(depth, tempTree);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\tTop down construction took %d msec\n",
               elapsedTime(tFinish - tStart));
            
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
                tempTree = MakeTree(depth);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\tBottom up construction took %d msec\n",
               elapsedTime(tFinish - tStart));

}

int main() {
        Node    root;
        Node    longLivedTree;
        Node    tempTree;
        long    tStart, tFinish;
        long    tElapsed;
   int i, d;
 double  *array;

#ifdef GC
 // GC_full_freq = 30;
 // GC_free_space_divisor = 16;
 // GC_enable_incremental();
#endif
 printf("Garbage Collector Test\n");
  printf(" Live storage will peak at %d bytes.\n\n",
               2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) +
               sizeof(double) * kArraySize);
        printf(" Stretching memory with a binary tree of depth %d\n",
               kStretchTreeDepth);
        PrintDiagnostics();
# ifdef PROFIL
     init_profiling();
# endif
      
        tStart = currentTime();
       
        // Stretch the memory space quickly
        tempTree = MakeTree(kStretchTreeDepth);
# ifndef GC
          destroy_Node(tempTree);
# endif
        tempTree = 0;

        // Create a long lived object
        printf(" Creating a long-lived binary tree of depth %d\n",
               kLongLivedTreeDepth);
# ifndef GC
          longLivedTree = calloc(1, sizeof(Node0));
# else
          longLivedTree = GC_NEW(Node0);
# endif
        Populate(kLongLivedTreeDepth, longLivedTree);

        // Create long-lived array, filling half of it
 printf(" Creating a long-lived array of %d doubles\n", kArraySize);
# ifndef GC
          array = malloc(kArraySize * sizeof(double));
# else
#   ifndef NO_PTRFREE
            array = GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
#   else
            array = GC_MALLOC(sizeof(double) * kArraySize);
#   endif
# endif
        for (i = 0; i < kArraySize/2; ++i) {
                array[i] = 1.0/i;
        }
        PrintDiagnostics();

        for (d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
                TimeConstruction(d);
        }

        if (longLivedTree == 0 || array[1000] != 1.0/1000)
  fprintf(stderr, "Failed\n");
                                // fake reference to LongLivedTree
                                // and array
                                // to keep them from being optimized away

        tFinish = currentTime();
        tElapsed = elapsedTime(tFinish-tStart);
        PrintDiagnostics();
        printf("Completed in %d msec\n", tElapsed);
# ifdef GC
   printf("Completed %d collections\n", GC_gc_no);
   printf("Heap size is %d\n", GC_get_heap_size());
#       endif
# ifdef PROFIL
   dump_profile();
# endif
}

 

* 쓰레기 수집기가 동작하지 않도록 컴파일하기
$ gcc -o GCBench GCBench.c -lgc

* 실행하기
$ ./GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
Creating 33824 trees of depth 4
        Top down construction took 378 msec
        Bottom up construction took 374 msec
Creating 8256 trees of depth 6
        Top down construction took 379 msec
        Bottom up construction took 357 msec
Creating 2052 trees of depth 8
        Top down construction took 379 msec
        Bottom up construction took 354 msec
Creating 512 trees of depth 10
        Top down construction took 383 msec
        Bottom up construction took 356 msec
Creating 128 trees of depth 12
        Top down construction took 382 msec
        Bottom up construction took 363 msec
Creating 32 trees of depth 14
        Top down construction took 387 msec
        Bottom up construction took 381 msec
Creating 8 trees of depth 16
        Top down construction took 396 msec
        Bottom up construction took 400 msec
Completed in 5525 msec

 

* 쓰레기 수집기가 동작하도록 컴파일하기
$ gcc -DGC -o GCBench GCBench.c -lgc

* 실행하기
$ ./GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
Creating 33824 trees of depth 4
        Top down construction took 44 msec
        Bottom up construction took 37 msec
Creating 8256 trees of depth 6
        Top down construction took 43 msec
        Bottom up construction took 39 msec
Creating 2052 trees of depth 8
        Top down construction took 38 msec
        Bottom up construction took 38 msec
Creating 512 trees of depth 10
        Top down construction took 38 msec
        Bottom up construction took 38 msec
Creating 128 trees of depth 12
        Top down construction took 44 msec
        Bottom up construction took 38 msec
Creating 32 trees of depth 14
        Top down construction took 38 msec
        Bottom up construction took 39 msec
Creating 8 trees of depth 16
        Top down construction took 38 msec
        Bottom up construction took 52 msec
Completed in 640 msec
Completed 25 collections
Heap size is 28975104

 

* 다중 쓰레드에서 쓰레기 수집  벤치마크 테스트 (파일명: MT_GCBench.c)

// This is adapted from a benchmark written by John Ellis and Pete Kovac
// of Post Communications.
// It was modified by Hans Boehm of Silicon Graphics.
// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
// Translated to C 15 March 2000 by Hans Boehm, now at HP Labs.
// Adapted to run NTHREADS client threads concurrently.  Each
// thread executes the original benchmark.  12 June 2000  by Hans Boehm.
//
//      This is no substitute for real applications.  No actual application
//      is likely to behave in exactly this way.  However, this benchmark was
//      designed to be more representative of real applications than other
//      Java GC benchmarks of which we are aware.
//      It attempts to model those properties of allocation requests that
//      are important to current GC techniques.
//      It is designed to be used either to obtain a single overall performance
//      number, or to give a more detailed estimate of how collector
//      performance varies with object lifetimes.  It prints the time
//      required to allocate and collect balanced binary trees of various
//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
//      allocates roughly the same amount of memory.
//      Two data structures are kept around during the entire process, so
//      that the measured performance is representative of applications
//      that maintain some live in-memory data.  One of these is a tree
//      containing many pointers.  The other is a large array containing
//      double precision floating point numbers.  Both should be of comparable
//      size.
//
//      The results are only really meaningful together with a specification
//      of how much memory was used.  It is possible to trade memory for
//      better time performance.  This benchmark should be run in a 32 MB
//      heap, though we don't currently know how to enforce that uniformly.
//
//      Unlike the original Ellis and Kovac benchmark, we do not attempt
//      measure pause times.  This facility should eventually be added back
//      in.  There are several reasons for omitting it for now.  The original
//      implementation depended on assumptions about the thread scheduler
//      that don't hold uniformly.  The results really measure both the
//      scheduler and GC.  Pause time measurements tend to not fit well with
//      current benchmark suites.  As far as we know, none of the current
//      commercial Java implementations seriously attempt to minimize GC pause
//      times.

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

#ifdef GC
#  ifndef LINUX_THREADS
#     define LINUX_THREADS
#  endif
#  ifndef _REENTRANT
#     define _REENTRANT
#  endif
#  ifdef LOCAL
#    define GC_REDIRECT_TO_LOCAL
#    include "gc_local_alloc.h"
#  endif
#  include "gc.h"
#endif


#ifndef NTHREADS
#   define NTHREADS 1
#endif

#ifdef PROFIL
  extern void init_profiling();
  extern dump_profile();
#endif

//  These macros were a quick hack for the Macintosh.
//
//  #define currentTime() clock()
//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)

#define currentTime() stats_rtclock()
#define elapsedTime(x) (x)

/* Get the current time in milliseconds */

unsigned
stats_rtclock( void )
{
  struct timeval t;
  struct timezone tz;

  if (gettimeofday( &t, &tz ) == -1)
    return 0;
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
}

static const int kStretchTreeDepth    = 18;      // about 16Mb
static const int kLongLivedTreeDepth  = 16;  // about 4Mb
static const int kArraySize  = 500000;  // about 4Mb
static const int kMinTreeDepth = 4;
static const int kMaxTreeDepth = 16;

typedef struct Node0_struct {
        struct Node0_struct * left;
        struct Node0_struct * right;
        int i, j;
} Node0;

#ifdef HOLES
#   define HOLE() GC_NEW(Node0);
#else
#   define HOLE()
#endif

typedef Node0 *Node;

void init_Node(Node me, Node l, Node r) {
    me -> left = l;
    me -> right = r;
}

#ifndef GC
  void destroy_Node(Node me) {
    if (me -> left) {
 destroy_Node(me -> left);
    }
    if (me -> right) {
 destroy_Node(me -> right);
    }
    free(me);
  }
#endif

// Nodes used by a tree of a given size
static int TreeSize(int i) {
        return ((1 << (i + 1)) - 1);
}

// Number of iterations to use for a given tree depth
static int NumIters(int i) {
        return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
}

// Build tree top down, assigning to older objects.
static void Populate(int iDepth, Node thisNode) {
        if (iDepth<=0) {
                return;
        } else {
                iDepth--;
#  ifdef GC
                  thisNode->left  = GC_NEW(Node0); HOLE();
                  thisNode->right = GC_NEW(Node0); HOLE();
#  else
                  thisNode->left  = calloc(1, sizeof(Node0));
                  thisNode->right = calloc(1, sizeof(Node0));
#  endif
                Populate (iDepth, thisNode->left);
                Populate (iDepth, thisNode->right);
        }
}

// Build tree bottom-up
static Node MakeTree(int iDepth) {
 Node result;
        if (iDepth<=0) {
#     ifndef GC
  result = calloc(1, sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     /* result is implicitly initialized in both cases. */
     return result;
        } else {
     Node left = MakeTree(iDepth-1);
     Node right = MakeTree(iDepth-1);
#     ifndef GC
  result = malloc(sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     init_Node(result, left, right);
     return result;
        }
}

static void PrintDiagnostics() {
#if 0
        long lFreeMemory = Runtime.getRuntime().freeMemory();
        long lTotalMemory = Runtime.getRuntime().totalMemory();

        System.out.print(" Total memory available="
                         + lTotalMemory + " bytes");
        System.out.println("  Free memory=" + lFreeMemory + " bytes");
#endif
}

static void TimeConstruction(int depth) {
        long    tStart, tFinish;
        int     iNumIters = NumIters(depth);
        Node    tempTree;
 int  i;

 printf("0x%x: Creating %d trees of depth %d\n", pthread_self(), iNumIters, depth);
       
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
#  ifndef GC
                  tempTree = calloc(1, sizeof(Node0));
#  else
                  tempTree = GC_NEW(Node0);
#  endif
                Populate(depth, tempTree);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Top down construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));
            
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
                tempTree = MakeTree(depth);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Bottom up construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));

}

void * run_one_test(void * arg) {
 int d;
        for (d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
                TimeConstruction(d);
        }
}

int main() {
        Node    root;
        Node    longLivedTree;
        Node    tempTree;
        long    tStart, tFinish;
        long    tElapsed;
   int i;
 double  *array;

#ifdef GC
 // GC_full_freq = 30;
 // GC_free_space_divisor = 16;
 // GC_enable_incremental();
#endif
#       if defined(GC) && defined(LOCAL)
   GC_thr_init();
#   endif
 printf("Garbage Collector Test\n");
  printf(" Live storage will peak at %d bytes.\n\n",
               2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) +
               sizeof(double) * kArraySize);
        printf(" Stretching memory with a binary tree of depth %d\n",
               kStretchTreeDepth);
        PrintDiagnostics();
# ifdef PROFIL
     init_profiling();
# endif
      
        tStart = currentTime();
       
        // Stretch the memory space quickly
        tempTree = MakeTree(kStretchTreeDepth);
# ifndef GC
          destroy_Node(tempTree);
# endif
        tempTree = 0;

        // Create a long lived object
        printf(" Creating a long-lived binary tree of depth %d\n",
               kLongLivedTreeDepth);
# ifndef GC
          longLivedTree = calloc(1, sizeof(Node0));
# else
          longLivedTree = GC_NEW(Node0);
# endif
        Populate(kLongLivedTreeDepth, longLivedTree);

        // Create long-lived array, filling half of it
 printf(" Creating a long-lived array of %d doubles\n", kArraySize);
# ifndef GC
          array = malloc(kArraySize * sizeof(double));
# else
#   ifndef NO_PTRFREE
            array = GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
#   else
            array = GC_MALLOC(sizeof(double) * kArraySize);
#   endif
# endif
        for (i = 0; i < kArraySize/2; ++i) {
                array[i] = 1.0/i;
        }

        {
   pthread_t thread[NTHREADS];
   for (i = 1; i < NTHREADS; ++i) {
         int code;

     if ((code = pthread_create(thread+i, 0, run_one_test, 0)) != 0) {
           fprintf(stderr, "Thread creation failed %u\n", code);
       exit(1);
     }
   }
   /* We use the main thread to run one test.  This allows */
   /* profiling to work, for example.    */
   run_one_test(0);
   for (i = 1; i < NTHREADS; ++i) {
         int code;
     if ((code = pthread_join(thread[i], 0)) != 0) {
         fprintf(stderr, "Thread join failed %u\n", code);
           }
    }
        }
        PrintDiagnostics();

        if (longLivedTree == 0 || array[1000] != 1.0/1000)
  fprintf(stderr, "Failed\n");
                                // fake reference to LongLivedTree
                                // and array
                                // to keep them from being optimized away

        tFinish = currentTime();
        tElapsed = elapsedTime(tFinish-tStart);
        PrintDiagnostics();
        printf("Completed in %d msec\n", tElapsed);
# ifdef GC
   printf("Completed %d collections\n", GC_gc_no);
   printf("Heap size is %d\n", GC_get_heap_size());
#       endif
# ifdef PROFIL
   dump_profile();
# endif
}

 

* 쓰레기 수집기가 동작하지 않도록 컴파일하기
$ gcc -o MT_GCBench MT_GCBench.c -lgc

* 실행하기
$ ./MT_GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 379 msec
        0x4b0038: Bottom up construction took 353 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 380 msec
        0x4b0038: Bottom up construction took 355 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 379 msec
        0x4b0038: Bottom up construction took 355 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 382 msec
        0x4b0038: Bottom up construction took 355 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 386 msec
        0x4b0038: Bottom up construction took 361 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 383 msec
        0x4b0038: Bottom up construction took 360 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 389 msec
        0x4b0038: Bottom up construction took 373 msec
Completed in 5423 msec

 

* 쓰레기 수집기가 동작하도록 컴파일하기
$ gcc -DGC -o MT_GCBench MT_GCBench.c -lgc

* 실행하기
$ ./MT_GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 52 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 44 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 44 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 51 msec
Completed in 651 msec
Completed 25 collections
Heap size is 28975104

 

 

* 다중 쓰레드에서 쓰레기 수집  벤치마크 테스트 2 (파일명: MT_GCBench2.c)

// This is version 2 of the multithreaded GC Bench.
// Heap expansion is handled differently from version 1, in an attempt
// to make scalability measurements more meaningful.  The version with
// N threads now immediately expands the heap to N*32MB.
//
// To run this with BDWGC versions 6 and later with thread local allocation,
// define GC and LOCAL.  Without thread-local allocation, define just GC.
// To run it with the University of Tokyo scalable GC,
// define SGC.  To run it with malloc and explicit deallocation, define
// none of these.  (This should also work for Hoard.)
//
// Note that defining GC or SGC removes the explicit deallocation passes,
// which seems fair.
//
// This is adapted from a benchmark written by John Ellis and Pete Kovac
// of Post Communications.
// It was modified by Hans Boehm of Silicon Graphics.
// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
// Translated to C 15 March 2000 by Hans Boehm, now at HP Labs.
// Adapted to run NTHREADS client threads concurrently.  Each
// thread executes the original benchmark.  12 June 2000  by Hans Boehm.
// Changed heap expansion rule, and made the number of threads run-time
// configurable.  25 Oct 2000 by Hans Boehm.
//
//      This is no substitute for real applications.  No actual application
//      is likely to behave in exactly this way.  However, this benchmark was
//      designed to be more representative of real applications than other
//      Java GC benchmarks of which we were aware at the time.
//      It still doesn't seem too bad for something this small.
//      It attempts to model those properties of allocation requests that
//      are important to current GC techniques.
//      It is designed to be used either to obtain a single overall performance
//      number, or to give a more detailed estimate of how collector
//      performance varies with object lifetimes.  It prints the time
//      required to allocate and collect balanced binary trees of various
//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
//      allocates roughly the same amount of memory.
//      Two data structures are kept around during the entire process, so
//      that the measured performance is representative of applications
//      that maintain some live in-memory data.  One of these is a tree
//      containing many pointers.  The other is a large array containing
//      double precision floating point numbers.  Both should be of comparable
//      size.
//
//      The results are only really meaningful together with a specification
//      of how much memory was used.  This versions of the benchmark tries
//      to preallocate a sufficiently large heap that expansion should not be
//      needed.
//
//      Unlike the original Ellis and Kovac benchmark, we do not attempt
//      measure pause times.  This facility should eventually be added back
//      in.  There are several reasons for omitting it for now.  The original
//      implementation depended on assumptions about the thread scheduler
//      that don't hold uniformly.  The results really measure both the
//      scheduler and GC.  Pause time measurements tend to not fit well with
//      current benchmark suites.  As far as we know, none of the current
//      commercial Java implementations seriously attempt to minimize GC pause
//      times.
//
//      Since this benchmark has recently been more widely used, some
//      anomalous behavious has been uncovered.  The user should be aware
//      of this:
//      1) Nearly all objects are of the same size.  This benchmark is
//         not useful for analyzing fragmentation behavior.  It is unclear
//         whether this is an issue for well-designed allocators.
//      2) Unless HOLES is defined, it tends to drop consecutively allocated
//         memory at the same time.  Many real applications do exhibit this
//         phenomenon, but probably not to this extent.  (Defining HOLES tends
//         to move the benchmark to the opposite extreme.)
//      3) It appears harder to predict object lifetimes than for most real
//         Java programs (see T. Harris, "Dynamic adptive pre-tenuring",
//         ISMM '00).

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

#ifdef GC
#  ifndef LINUX_THREADS
#     define LINUX_THREADS
#  endif
#  ifndef _REENTRANT
#     define _REENTRANT
#  endif
#  ifdef LOCAL
#    define GC_REDIRECT_TO_LOCAL
#    include "gc_local_alloc.h"
#  endif
#  include "gc.h"
#endif
#ifdef SGC
#  include "sgc.h"
#  define GC
#  define pthread_create GC_pthread_create
#  define pthread_join GC_pthread_join
#endif

#define MAX_NTHREADS 1024

int nthreads = 0;

#ifdef PROFIL
  extern void init_profiling();
  extern dump_profile();
#endif

//  These macros were a quick hack for the Macintosh.
//
//  #define currentTime() clock()
//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)

#define currentTime() stats_rtclock()
#define elapsedTime(x) (x)

/* Get the current time in milliseconds */

unsigned
stats_rtclock( void )
{
  struct timeval t;
  struct timezone tz;

  if (gettimeofday( &t, &tz ) == -1)
    return 0;
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
}

static const int kStretchTreeDepth    = 18;      // about 16Mb
static const int kLongLivedTreeDepth  = 16;  // about 4Mb
static const int kArraySize  = 500000;  // about 4Mb
static const int kMinTreeDepth = 4;
static const int kMaxTreeDepth = 16;

typedef struct Node0_struct {
        struct Node0_struct * left;
        struct Node0_struct * right;
        int i, j;
} Node0;

#ifdef HOLES
#   define HOLE() GC_NEW(Node0);
#else
#   define HOLE()
#endif

typedef Node0 *Node;

void init_Node(Node me, Node l, Node r) {
    me -> left = l;
    me -> right = r;
}

#ifndef GC
  void destroy_Node(Node me) {
    if (me -> left) {
 destroy_Node(me -> left);
    }
    if (me -> right) {
 destroy_Node(me -> right);
    }
    free(me);
  }
#endif

// Nodes used by a tree of a given size
static int TreeSize(int i) {
        return ((1 << (i + 1)) - 1);
}

// Number of iterations to use for a given tree depth
static int NumIters(int i) {
        return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
}

// Build tree top down, assigning to older objects.
static void Populate(int iDepth, Node thisNode) {
        if (iDepth<=0) {
                return;
        } else {
                iDepth--;
#  ifdef GC
                  thisNode->left  = GC_NEW(Node0); HOLE();
                  thisNode->right = GC_NEW(Node0); HOLE();
#  else
                  thisNode->left  = calloc(1, sizeof(Node0));
                  thisNode->right = calloc(1, sizeof(Node0));
#  endif
                Populate (iDepth, thisNode->left);
                Populate (iDepth, thisNode->right);
        }
}

// Build tree bottom-up
static Node MakeTree(int iDepth) {
 Node result;
        if (iDepth<=0) {
#     ifndef GC
  result = calloc(1, sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     /* result is implicitly initialized in both cases. */
     return result;
        } else {
     Node left = MakeTree(iDepth-1);
     Node right = MakeTree(iDepth-1);
#     ifndef GC
  result = malloc(sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     init_Node(result, left, right);
     return result;
        }
}

static void PrintDiagnostics() {
#if 0
        long lFreeMemory = Runtime.getRuntime().freeMemory();
        long lTotalMemory = Runtime.getRuntime().totalMemory();

        System.out.print(" Total memory available="
                         + lTotalMemory + " bytes");
        System.out.println("  Free memory=" + lFreeMemory + " bytes");
#endif
}

static void TimeConstruction(int depth) {
        long    tStart, tFinish;
        int     iNumIters = NumIters(depth);
        Node    tempTree;
 int  i;

 printf("0x%x: Creating %d trees of depth %d\n", pthread_self(), iNumIters, depth);
       
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
#  ifndef GC
                  tempTree = calloc(1, sizeof(Node0));
#  else
                  tempTree = GC_NEW(Node0);
#  endif
                Populate(depth, tempTree);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Top down construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));
            
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
                tempTree = MakeTree(depth);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Bottom up construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));

}

void * run_one_test(void * arg) {
 int d, i;
        Node    longLivedTree;
 double  *array;
 /* size_t initial_bytes = GC_get_total_bytes(); */

        // Create a long lived object
        printf(" Creating a long-lived binary tree of depth %d\n",
               kLongLivedTreeDepth);
# ifndef GC
          longLivedTree = calloc(1, sizeof(Node0));
# else
          longLivedTree = GC_NEW(Node0);
# endif
        Populate(kLongLivedTreeDepth, longLivedTree);

        // Create long-lived array, filling half of it
 printf(" Creating a long-lived array of %d doubles\n", kArraySize);
# ifndef GC
          array = malloc(kArraySize * sizeof(double));
# else
#   ifndef NO_PTRFREE
            array = GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
#   else
            array = GC_MALLOC(sizeof(double) * kArraySize);
#   endif
# endif
        for (i = 0; i < kArraySize/2; ++i) {
                array[i] = 1.0/i;
        }

        for (d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
                TimeConstruction(d);
        }
 /* printf("Allocated %ld bytes before start, %ld after\n",
  initial_bytes, GC_get_total_bytes() - initial_bytes); */
        if (longLivedTree->left -> right == 0 || array[1000] != 1.0/1000)
  fprintf(stderr, "Failed\n");
                                // fake reference to LongLivedTree
                                // and array
                                // to keep them from being optimized away

}

int main(int argc, char **argv) {
        Node    root;
        Node    tempTree[MAX_NTHREADS];
        long    tStart, tFinish;
        long    tElapsed;
   int i;
# ifdef SGC
   SGC_attr_t attr;
# endif

 if (1 == argc) {
     nthreads = 1;
 } else if (2 == argc) {
     nthreads = atoi(argv[1]);
     if (nthreads < 1 || nthreads > MAX_NTHREADS) {
  fprintf(stderr, "Invalid # of threads argument\n");
  exit(1);
     }
 } else {
     fprintf(stderr, "Usage: %s [# of threads]\n");
     exit(1);
 }
#       if defined(SGC)
   /* The University of Tokyo collector needs explicit */
   /* initialization.     */
   SGC_attr_init(&attr);
   SGC_init(nthreads, &attr);
#   endif
#ifdef GC
 // GC_full_freq = 30;
 // GC_free_space_divisor = 16;
 // GC_enable_incremental();
#endif
 printf("Garbage Collector Test\n");
  printf(" Live storage will peak at %d bytes or less .\n\n",
               2 * sizeof(Node0) * nthreads
          * (TreeSize(kLongLivedTreeDepth) + TreeSize(kMaxTreeDepth))
               + sizeof(double) * kArraySize);
        PrintDiagnostics();
       
# ifdef GC
   /* GC_expand_hp fails with empty heap */
   GC_malloc(1);
   GC_expand_hp(32*1024*1024*nthreads);
# endif

# ifdef PROFIL
     init_profiling();
# endif
      
        tStart = currentTime();
        {
   pthread_t thread[MAX_NTHREADS];
   for (i = 1; i < nthreads; ++i) {
         int code;

     if ((code = pthread_create(thread+i, 0, run_one_test, 0)) != 0) {
           fprintf(stderr, "Thread creation failed %u\n", code);
       exit(1);
     }
   }
   /* We use the main thread to run one test.  This allows */
   /* profiling to work, for example.    */
   run_one_test(0);
   for (i = 1; i < nthreads; ++i) {
         int code;
     if ((code = pthread_join(thread[i], 0)) != 0) {
         fprintf(stderr, "Thread join failed %u\n", code);
           }
    }
        }
        PrintDiagnostics();

        tFinish = currentTime();
        tElapsed = elapsedTime(tFinish-tStart);
        PrintDiagnostics();
        printf("Completed in %d msec\n", tElapsed);
# ifdef GC
   printf("Completed %d collections\n", GC_gc_no);
   printf("Heap size is %d\n", GC_get_heap_size());
#       endif
# ifdef PROFIL
   dump_profile();
# endif
        return 0;
}

 

* 쓰레기 수집기가 동작하지 않도록 컴파일하기
$ gcc -o MT_GCBench2 MT_GCBench2.c -lgc

* 실행하기
$ ./MT_GCBench2
Garbage Collector Test
 Live storage will peak at 12388544 bytes or less .

 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 396 msec
        0x4b0038: Bottom up construction took 379 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 399 msec
        0x4b0038: Bottom up construction took 396 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 385 msec
        0x4b0038: Bottom up construction took 368 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 419 msec
        0x4b0038: Bottom up construction took 380 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 399 msec
        0x4b0038: Bottom up construction took 360 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 414 msec
        0x4b0038: Bottom up construction took 358 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 415 msec
        0x4b0038: Bottom up construction took 402 msec
Completed in 5504 msec

 

* 쓰레기 수집기가 동작하도록 컴파일하기
$ gcc -DGC -o MT_GCBench2 MT_GCBench2.c -lgc

* 실행하기
$ ./MT_GCBench2
Garbage Collector Test
 Live storage will peak at 12388544 bytes or less .

 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 54 msec
        0x4b0038: Bottom up construction took 41 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 40 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 40 msec
        0x4b0038: Bottom up construction took 42 msec
Completed in 581 msec
Completed 14 collections
Heap size is 33619968

 

 

 

 

Posted by Scripter

댓글을 달아 주세요

 

 

C 언어 소스:

// Filename: testHexView_02.c
//
//  Chapter 1.  Section 1.
//
//       A basic pattern of C++ Programing
//
// Compile: gcc -o testHexView_02 testHexView_02.c

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h> 

void toHex(char c, char a[3]);
void toHex8(int n, char a[10]);

int main(int argc, char *argv[])
{
    char *fname;
     FILE *file2;

    fpos_t fsize;
    long m;
    int i;

    char x;
    char s[3];
    char t[10];
    char buf[16];
    fpos_t n = 0L;

    struct stat stt;


    if (argc < 2)
    {
        printf("Usage: testHexView_02 [filename]\n");
        exit( 1 );
    }

    fname = argv[1];

    if (stat(fname, &stt) == 0 )
    {
        if ( stt.st_mode & S_IFDIR )
        {
            printf("\"%s\" is a directory\n", fname);
            exit( 1 );
        }
    }
   
    if (access(fname, R_OK) != 0)
    {
        printf("The file: \"%s\" is not readble.\n", fname);
        exit( 1 );
    }
 
    file2 = fopen(fname, "rb");

    if (!file2)
    {
        printf("Fail to open the file: \"%s\".\n", fname);
        exit( 1 );
    }

    s[2] = '\0';
    t[4] = ' ';
    t[9] = '\0';
    if (file2)
    {
        fseek(file2, 0, SEEK_END);    // seek to end of file
        fsize = ftell(file2);                 // get current file pointer

        printf("Its file size is %ld.\n\n", fsize);

        fseek(file2, 0, SEEK_SET);

        while(n < fsize && !feof(file2))
        {
            toHex8(n, t);
            printf("%s: ", t);
      
            fread(buf, sizeof(buf), 1, file2);
            m = (((fsize - n) < 16L) ? (long) (fsize - n) : 16L);
            for (i = 0; i < m; i++)
            {
                x = buf[i];
                toHex(x, s);
                printf("%s", s);
                if (i == 7)
                    printf("-");
                else
                    printf(" ");
            }
            if (m < 16)
            {
                for (i = 0; i < 16 - m; i++)
                {
                    printf("   ");
                }
            }

            printf("|");
            for (i = 0; i < m; i++)
            {
                if (buf[i] < ' ')
                    printf(".");
                else
                    printf("%c", buf[i]);
            }
            if (m < 16)
            {
                for (i = 0; i < 16 - m; i++)
                {
                    printf(" ");
                }
            }
            printf("|");

            n += m;
            printf("\n");
        }

        fclose(file2);
      
        printf("\n");;
        printf("Read %ld bytes.\n", n);
    }
    else {
        printf("Fail to read the file: \"%s\".,", fname);
    }
}

void toHex(char c, char a[3]) {
    int x1, x2;
    x1 = (c & 0xF0) >> 4;
    x2 = c & 0x0F;
    if (x1 < 10)
        a[0] = x1 + '0';
    else
        a[0] = (x1 - 10) + 'A';
    if (x2 < 10)
        a[1] = x2 + '0';
    else
        a[1] = (x2 - 10) + 'A';
}

void toHex8(int n, char a[10]) {
    int x1, x2, x3, x4, x5, x6, x7, x8;
    x1 = (n & 0xF0000000) >> 28;
    x2 = (n & 0xF000000) >> 24;
    x3 = (n & 0xF00000) >> 20;
    x4 = (n & 0xF0000) >> 16;
    x5 = (n & 0xF000) >> 12;
    x6 = (n & 0xF00) >> 8;
    x7 = (n & 0xF0) >> 4;
    x8 = n & 0x0F;
    if (x1 < 10)
        a[0] = x1 + '0';
    else
        a[0] = (x1 - 10) + 'A';
    if (x2 < 10)
        a[1] = x2 + '0';
    else
        a[1] = (x2 - 10) + 'A';
    if (x3 < 10)
        a[2] = x3 + '0';
    else
        a[2] = (x3 - 10) + 'A';
    if (x4 < 10)
        a[3] = x4 + '0';
    else
        a[3] = (x4 - 10) + 'A';
    a[4] = ' ';
    if (x5 < 10)
        a[5] = x5 + '0';
    else
        a[5] = (x5 - 10) + 'A';
    if (x6 < 10)
        a[6] = x6 + '0';
    else
        a[6] = (x6 - 10) + 'A';
    if (x7 < 10)
        a[7] = x7 + '0';
    else
        a[7] = (x7 - 10) + 'A';
    if (x8 < 10)
        a[8] = x8 + '0';
    else
        a[8] = (x8 - 10) + 'A';
}

 

 

MinGW의 gcc로 컴파일하기> gcc -o testHexView_02 testHexView_02.cpp

 

실행 예 1> testHexView_02 temp_1.bin
Its file size is 12.

0000 0000: 48 65 6C 6C 6F 20 74 68-65 72 65 0A             |Hello there.    |

Read 12 bytes.

 

실행 예 2> testHexView_02 myFile.ser
Its file size is 130.

0000 0000: AC ED 00 05 73 72 00 06-50 65 72 73 6F 6E 07 31 |....sr..Person.1|
0000 0010: 46 DB A5 1D 44 AB 02 00-03 49 00 03 61 67 65 4C |F...D....I..ageL|
0000 0020: 00 09 66 69 72 73 74 4E-61 6D 65 74 00 12 4C 6A |..firstNamet..Lj|
0000 0030: 61 76 61 2F 6C 61 6E 67-2F 53 74 72 69 6E 67 3B |ava/lang/String;|
0000 0040: 4C 00 08 6C 61 73 74 4E-61 6D 65 71 00 7E 00 01 |L..lastNameq.~..|
0000 0050: 78 70 00 00 00 13 74 00-05 4A 61 6D 65 73 74 00 |xp....t..Jamest.|
0000 0060: 04 52 79 61 6E 73 71 00-7E 00 00 00 00 00 1E 74 |.Ryansq.~......t|
0000 0070: 00 07 4F 62 69 2D 77 61-6E 74 00 06 4B 65 6E 6F |..Obi-want..Keno|
0000 0080: 62 69                                           |bi              |

Read 130 bytes.

 

 

Posted by Scripter

댓글을 달아 주세요