시작하며..

0.6.4 버전의 카산드라(Cassandra)를 패치한 0.6.5의 큰 변화는 리눅스 운영체제에 동작하는 java 프로세스가 mmap을 사용하면서 swap 메모리가 증가되는 부분을 막기 위함이다.

아래 내용은 이 글을 이해하기 위한 작은 정보이다.

http://knight76.tistory.com/entry/Swap-메모리
http://knight76.tistory.com/entry/자바-RandomAccessFile-클래스의-map-메서드-내부-구조-분석

 

본론..

<이슈와 결과 내용>

0.6.4버전의 카산드라에서 read 성능이 너무 낮아졌고, swap 메모리가 많아지면서 성능이 떨어졌다고 한다.

(https://issues.apache.org/jira/browse/CASSANDRA-1214)

아래와 같이 성능이 어느 정도 나오지 못하고 들쑥날쑥 하고 있다.

JVM의 full gc 시간이 항상 일어나지 않는다. native heap 의 영역의 메모리가 많아져서 swap memory로 갔다가 gc time 때 swap으로부터 메모리를 읽은 후 gc 데이터를 모두 날리는 작업을 하면서 성능이 떨어지는 것이다.

gc 시점 때 all stop + swap in/out이 일어나면서 계속 성능이 저하되는 현상이 생긴 것이다.
(마치 gc 그래프와 흡사한 성능 그래프가 증명하고 있다.)

0.6.5 버전에서는 0.6.5 버전의 패치를 통해서 13%의 성능 향상이 일어났다.

 

<자세한 내용>

카산드라 0.6.4 버전에서는 SSTable read 성능을 높이기 위해서 NIO를 사용했다. 내부 데이터를 MappedByteBuffer 클래스로 읽는다. 이 때 mmap을 사용한다.

storage-conf.xml 설정 파일의 DisAccessMode 속성의 값은 auto이다.

<DiskAccessMode>auto</DiskAccessMode>

 

DatabaseDescritor 클래스의 static 블럭에서 파일을 읽고 있으며 64비트 머신인 경우에는 mmap이 디폴트값으로 정해진다.

String modeRaw = xmlUtils.getNodeValue("/Storage/DiskAccessMode");
diskAccessMode = DiskAccessMode.valueOf(modeRaw);
if (diskAccessMode == DiskAccessMode.auto) {
          diskAccessMode = System.getProperty("os.arch").contains("64") ?
          DiskAccessMode.mmap
: DiskAccessMode.standard;
          indexAccessMode = diskAccessMode;
}

 

disk access mode 의 값이 standard인 경우는 index buffer 자체가 없기 때문에 큰 성능을 기대할 수는 없지만, mmap 모드인 경우에는 index buffer를 메모리에 사용할 수 있다.

SSTableReader 클래스 생성자 에서는 mmap disk access의 경우 mmap을 사용할 수 있도록 되어 있다.

    long indexLength = new File(indexFilename()).length();
    int bufferCount = 1 + (int) (indexLength / BUFFER_SIZE);
    indexBuffers = new MappedByteBuffer[bufferCount];
    long remaining = indexLength;
    for (int i = 0; i < bufferCount; i++)
    {
        indexBuffers[i] = mmap(indexFilename(), i * BUFFER_SIZE,
                                 (int) Math.min(remaining, BUFFER_SIZE));
        remaining -= BUFFER_SIZE;
    }

 

mmap 메서드는 다음과 같이 정의되어 있다.

private static MappedByteBuffer mmap(String filename, long start, int size) throws IOException
{
    RandomAccessFile raf;
    try
    {
        raf = new RandomAccessFile(filename, "r");
    }
    catch (FileNotFoundException e)
    {
        throw new IOError(e);
    }

    try
    {
        return raf.getChannel().map(FileChannel.MapMode.READ_ONLY, start, size);
    }
    finally
    {
        raf.close();
    }
}


RandromAccessFile 클래스의 map 메서드는 내부적으로 clib의 공유할 수 있는 mmap64 시스템콜을 호출하여 native heap 영역의 메모리를 공유한다. (참고 : http://knight76.tistory.com/entry/자바-RandomAccessFile-클래스의-map-메서드-내부-구조-분석)

 

<버그질라 이슈에 대한 설명>

리눅스 커널의 메모리 관리자는 swap 메모리로 언제든지 데이터를 옮길 수 있다.
리눅스 커널의 vm.swappiness 파라미터가 0 이상이면 메모리가 어느 정도 부족하다고 판단하면 swap 메모리로 옮겨놨다가 필요할 때 램에 적재하게 한다.

mmap을 쓰다보니 native heap 영역에 있는 데이터들의 gc 가 되는 시점이 중요해진다.  java의 heap 영역을 청소하는 full gc 가 호출 될 때 unmap이 호출이 되는 구조로 되어 있다. (참고 : http://knight76.tistory.com/entry/자바-RandomAccessFile-클래스의-map-메서드-내부-구조-분석). unmap이 되는 클래스가 PhantomReference를 상속하였는데, 이 의미는 정말 사용 중이지 않을 때 gc 대상이 된다. (전문 용어로 reachable 하지 않거나 referent 객체로부터 로부터 mark되지 않은 상태). soft reference나 weak reference 보다도 최대한 끝까지 살아남는 놈들이다.  (자바 스펙에는 모호하게 적혀 있고, java.lang.ref api와 소스에서 그 의미를 찾아볼 수 있다.)

full gc가 일어나는 시점에서 본다면, native heap 영역이 가득차거나 java heap 영역이 가득찰 때 일어난다. (사실 정확하게 찬다는 의미보다는 gc가 적당한 비율로 메모리를 찼다고 판단하면 gc한다.) 결국은 많은 메모리를 사용 중에 일어날 수 있다.

리눅스 커널은 mmap으로 할당받은 데이터인 SSTable의 정보를 swap 메모리로 이동한다. 무식한 이 데이터는 full gc에도 차곡차곡 쌓이다가 정말 확실히 gc의 대상이 될 때, gc가 된다.
이 때, gc 시점에 정리를 하는데, swap 영역에 있는 녀석이 gc가 될 수 없다. 즉 swap in(ram으로 불러들임)을 한후, gc가 된다. 만약 swap 영역의 메모리가 ram 메모리의 크기보다 많이 크다면 성능은 전혀 기대할 수 없는 수준으로 내려갈 수 밖에 없다.

따라서, 만약 적당한 크기의 swap 영역을 지정할 필요가 있다.  이 영역을 제대로 잡는 것은 계속적인 테스트를 통해서만 할 수 있다.

이런 부분 때문에 카산드라에서는 swaping 셋팅을 전혀 안하는 것이 최고의 선택(best value)라고 하는 배경이다.

http://wiki.apache.org/cassandra/MemtableThresholds

Virtual Memory and Swap

On a dedicated cassandra machine, the best value for your swap settings is no swap at all -- it's better to have the OS kill the java process (taking the node down but leaving your monitoring, etc. up) than to have the system go into swap death (and become entirely unreachable).

Linux users should understand fully and then consider adjusting the system values for swappiness, overcommit_memory and overcommit_ratio.

 

http://wiki.apache.org/cassandra/FAQ#mmap

Why does top report that Cassandra is using a lot more memory than the Java heap max?

Cassandra uses mmap to do zero-copy reads. That is, we use the operating system's virtual memory system to map the sstable data files into the Cassandra process' address space. This will "use" virtual memory; i.e. address space, and will be reported by tools like top accordingly, but on 64 bit systems virtual address space is effectively unlimited so you should not worry about that.

What matters from the perspective of "memory use" in the sense as it is normally meant, is the amount of data allocated on brk() or mmap'd /dev/zero, which represent real memory used. The key issue is that for a mmap'd file, there is never a need to retain the data resident in physical memory. Thus, whatever you do keep resident in physical memory is essentially just there as a cache, in the same way as normal I/O will cause the kernel page cache to retain data that you read/write.

The difference between normal I/O and mmap() is that in the mmap() case the memory is actually mapped to the process, thus affecting the virtual size as reported by top. The main argument for using mmap() instead of standard I/O is the fact that reading entails just touching memory - in the case of the memory being resident, you just read it - you don't even take a page fault (so no overhead in entering the kernel and doing a semi-context switch). This is covered in more detail here.

 

그럼에도 불구하고, 최근에 릴리즈된 1.0.2소스를 보니 DiskAccessMode의 디폴트값이 auto로 되어 있다. 이는니눅스  64 비트 운영체제를 사용하는 신규 개발자에게는 재앙이 될 수 있다는 얘기도 된다.

1.0.2에서는 약간 구조를 바꾸어서 쓰고 있으며, Table .getDataFileLocation() 호출시 적당한 시점에 System.gc()도 및 unmap를 통해서 메모리가 적당히 있을 수 있도록 수정되었다.  (정확히 말하면, 언제부터 바뀐지는 잘 모르지만, 많이 노력하고 있다는 느낌이다.

 

<mlockall의 사용>

0.6.5에서 바뀐 부분은 mlockall 메서드를 사용할 수 있도록 한 부분이다. 이를 위해서 JNA를 사용하였다. (참조 : http://knight76.tistory.com/entry/jni-vs-jna)

ivy.xml 설정 파일에 jna library가 추가되었다.

<dependency org="net.java.dev.jna" name="jna" rev="3.2.7"/>

ivysettings 설정 파일이 추가되었다.

<ivysettings>
  <settings defaultResolver="ibiblio"/>
  <resolvers>
    <chain name="chain" dual="true">
      <ibiblio name="java.net2" root="http://download.java.net/maven/2/" m2compatible="true"/>
      <ibiblio name="ibiblio" m2compatible="true" />
    </chain>
  </resolvers>
  <modules>
    <module organisation="net.java.dev.jna" name="jna" resolver="chain" />
  </modules>
</ivysettings>

 

CassandraDaemon 클래스의 setup 메서드안에서  FBUtilities.tryMlockall(); 을 호출한다. tryMlockall() 에서는 clib의 mlockAll() 시스템 콜을 호출한다. 즉 처음부터 nio 로 만든 객체들을 swap 메모리로 가지 않게 하고, ram에서만 사용할 수 있도록 바뀐 것이다.


public static void tryMlockall()
{
    int errno = Integer.MIN_VALUE;
    try
    {
       int result = CLibrary.mlockall(CLibrary.MCL_CURRENT);
        if (result != 0)
            errno = Native.getLastError();
    }
    catch (UnsatisfiedLinkError e)
    {
        // this will have already been logged by CLibrary, no need to repeat it
        return;
    }
    catch (Exception e)
    {
        logger_.debug("Unable to mlockall", e);
        // skipping mlockall doesn't seem to be a Big Deal except on Linux.  See CASSANDRA-1214
        if (System.getProperty("os.name").toLowerCase().contains("linux"))
        {
            logger_.warn("Unable to lock JVM memory (" + e.getMessage() + ")."
                         + " This can result in part of the JVM being swapped out, especially with mmapped I/O enabled.");
        }
        else if (!System.getProperty("os.name").toLowerCase().contains("windows"))
        {
            logger_.info("Unable to lock JVM memory: " + e.getMessage());
        }
        return;
    }

    if (errno != Integer.MIN_VALUE)
    {
        if (errno == CLibrary.ENOMEM && System.getProperty("os.name").toLowerCase().contains("linux"))
        {
            logger_.warn("Unable to lock JVM memory (ENOMEM)."
                         + " This can result in part of the JVM being swapped out, especially with mmapped I/O enabled."
                         + " Increase RLIMIT_MEMLOCK or run Cassandra as root.");
        }
        else if (!System.getProperty("os.name").toLowerCase().contains("mac"))
        {
            // OS X allows mlockall to be called, but always returns an error
            logger_.warn("Unknown mlockall error " + errno);
        }
    }
}

 

이런 용도로 CLibrary 클래스가 추가되었다.

public final class CLibrary
{
    private static Logger logger = LoggerFactory.getLogger(CLibrary.class);

    public static final int MCL_CURRENT = 1;
    public static final int MCL_FUTURE = 2;
   
    public static final int ENOMEM = 12;

    static
    {
        try
        {
            Native.register("c");
        }
        catch (NoClassDefFoundError e)
        {
            logger.info("JNA not found. Native methods will be disabled.");
        }
        catch (UnsatisfiedLinkError e)
        {
            logger.info("Unable to link C library. Native methods will be disabled.");
        }
    }

    public static native int mlockall(int flags);

    public static native int munlockall();

    private CLibrary() {}
}

 

참고로 munlockall() 메서드도 native로 바인딩되었지만 1.0.2에서도 실제 사용하지 않고 있다.

 

 

마치며..

2일 동안 카산드라의 파일 시스템쪽이 어떻게 되어 있는지 잘 몰랐는데. 이번 기회에 카산드라의 mmap 이슈와 그 처리방법에 대해서 잘 파악할 수 있었다. 시간이 되면 카산드라 분석해볼까나…

 

 

 

* 참고 내용 : mlock, mlockall (man 페이지를 이용한 정보 처리)


mlock, mlockall, munlock, munlockall 시스템 콜 함수에 대한 정리
"man mlock" 명령어를 사용하면 mlock 에 대한 정보를 확인할 수 있다.

       #include <sys/mman.h>

       int mlock(const void *addr, size_t len);

       int munlock(const void *addr, size_t len);

       int mlockall(int flags);

       int munlockall(void);

man mlock 에 대한 결과값을 확인할 수 있다.

mlock() 또는 mlockall()은 swap 영역으로 메모리 이동이 되지 않도록 RAM 안에 사용된 virtual memory(가상 주소)를 lock 한다.
munlock() 또는 munlockall()은 리눅스 커널 메모리 관리자에 의해서 swap out될 수 있도록 unlock해주는 함수이다.

mlock() 함수는 주소와 길이에 대한 영역을 lock을 개런티한다.
mlockall() 함수는 프로세스에 대한 주소번지 모두를 lock 한다.
코드/데이터/스택/동적라이르리러,사용자 커널데이터/공유메모리/메모리맵 데이터까지모두 lock한다.

mlockall() 의 아규먼트는 int형 타입의 flag 값을 지정하면 된다. 아래 타입 중에 하나만 또는 OR로 사용가능하다.

- MCL_CURRENT (1): 프로세스의 주소 영역으로 매핑된 모든 페이지
- MCL_FUTURE (2) : 앞으로 프로세스의 주소 영역에 매필될 모든 페이지.
               이 옵션을 사용하면 메모리 할당과 같은 시스템 콜(mmap, sbrk, malloc)을 쓰다 RAM 영역을 넘어설때 할당을 해주지 못하게 된다.
               만약 Stack에서 그 일이 발생하면, SIGSEGV signal이 발생하고 stack 영역은 확장을 할 수 없다.

 

Memory locking은 두 개의 주요 어플리케이션에 사용할 수 있다. real time 알고리즘과 보안을 높이 필요로 하는 데이터 처리쪽에 사용할 수 있다.
특히 real time 알고리즘이 필요한 어플리케이션에서는 locking 함으로서, page fault를 원천적으로 봉쇄해서
time-critical section(시간 동기 문제)가 일어나지 않게 할 수 있다.

 

Cassandra 0.6.5~1.0.2 (최신) 까지 mlockall(MCL_CURRENT)을 주어 사용하고 있음. 따라서 언제든지 차곡차곡 쌓이는 일부 메모리는 swap 메모리로 늘어날 수 있음..

Posted by 김용환 '김용환'

Swap 메모리

c or linux 2012.01.05 12:04

 

시작하며..

리눅스의 swap 메모리에 대해서 이해한다.

 

본론

만약 어플리케이션의 RAM 용량이 차면, swap 메모리가 자동으로 늘어나도록 되어 있다. 하드디스크의 디스크를 swap 메모리로 만들기 때문에 속도가 느려진다. 또한 RAM의 용량보다 2배로 swap 메모리를 잡도록 되어 있다. (참조 : http://vr.org/docs/centos/4/html/rhel-sag-en-4/ch-swapspace.html) 시스템 엔지니어는 이런 이슈로 리눅스 서버를 셋팅할 때 swap 영역을 얼마나 잡을지 판단해야 한다. 때로는 개발자가 이 부분을 고쳐 성능을 향상 시킬 수 있다. (참고 : https://wiki.archlinux.org/index.php/Swap)


개인적으로는 메모리가 갑자기 부족한 경우를 제외하고는 swap 자체를 안쓰는 것을 선호한다. 성능상 swap 메모리를 쓰는 것보다 swap in , swap out이 성능을 무너뜨리는 것을 많이 봐왔다. 또한 너무 크게 사용하는 것도 경계한다. (난 보수적인 사람이 되었나 보다… 아직 적절히 활용한 대용량 처리 사례를 못해봐서 그런지도 모르겠다. ) 차라리 RAM 하나 더 꽂는게 더 나은 것 같다. 

하지만 DB나, 오픈 소스 대용량 처리 어플리케이션의 경우에서는 swap을 많이 활용하려고 하고 있다는 사실이다. 어떻게 하든 속도를 내기 위해서 메모리에서 처리하려다 보니 swap을 쓸 수 밖에 없는 구조로 가고, 너무 많이 써서 문제가 되니 다시 mlock으로 막는 구조로 가는 부분으로 처리하는 형태로 가고 있다.

 

1. swap 및 ram 메모리 상태 보기

free 명령어를 이용해서 간단히 살펴볼 수 있다.

# free
             total       used       free     shared    buffers     cached
Mem:       4150252    3991868     158384          0      78504    2265916
-/+ buffers/cache:    1647448    2502804
Swap:      2096472        208    2096264

 

2. Swap 메모리 설정하는 방법

리눅스 커널 2.6부터 swap 메모리를 설정할 수 있다. swap 영역은 dd 명령어와 mkswap 명령어를 이용해서 swap을 만들 수 있다. (http://www.artwork.com/gdsii/qckvu/faq/linux_swap.htm) 이렇게 만들어진 영역은 swap 메모리로 쓰고 있다는 뜻이다. 아래의 예는 swap을 2G 정도만 쓰고 있다는 것을 의미한다.

# cat /proc/swaps
Filename                                Type            Size    Used    Priority
/dev/cciss/c0d0p2                 partition       2096472    208        -1

 

3. Swap 메모리 사용 빈도 설정 방법

swap 메모리를 사용 빈도를 확인하는 방법은 vm.swappiness 정보를 보는 것이다. centos를 비롯한 일부 서버는 디폴트로 60으로 잡혀 있다.

]# sysctl vm.swappiness   (또는 cat /proc/sys/vm/swappiness 으로 확인 가능)
vm.swappiness = 60

vm.swapiness 정보는 커널 파라미터이며 swap 영역을 얼마나 더 보겠냐 (또는 회피하겠냐)는 의미를 가지고 있다. (kernel's preference (or avoidance) of swap space) 여기에 0의 값을 넣으면 swap을 최대한 쓰지 않겠다는 의미이다. 만약 100은 하드디스크의 swap영역을 최대한 활용하겠다는 의미이다.

제일 이슈는 swap 메모리가 많이 잡혀 있는 것보다 얼마나 사용하고 있는지를 측정하는 것이 좋다. free나 cat /proc/swaps 명령어를 이용해서 해결할 수 있다.

만약 swap 메모리를 쓰지 않으려면, vm.swappiness를 0으로 셋팅하면 된다.

/etc/sysctl.conf 에 ‘vm.swappiness=0 ‘ 설정을 추가하고, ‘echo 0 > /proc/sys/vm/swappiness ‘ 명령어를 이용해서 적용한다.


* Reference

http://forums.gentoo.org/viewtopic.php?t=175419

5. Swappiness (2.6 kernels)
Since 2.6, there has been a way to tune how much Linux favors swapping out to disk compared to shrinking the caches when memory gets full.

ghoti adds:
When an application needs memory and all the RAM is fully occupied, the kernel has two ways to free some memory at its disposal: it can either reduce the disk cache in the RAM by eliminating the oldest data or it may swap some less used portions (pages) of programs out to the swap partition on disk.
It is not easy to predict which method would be more efficient.
The kernel makes a choice by roughly guessing the effectiveness of the two methods at a given instant, based on the recent history of activity.

Before the 2.6 kernels, the user had no possible means to influence the calculations and there could happen situations where the kernel often made the wrong choice, leading to thrashing and slow performance. The addition of swappiness in 2.6 changes this. 


 

또한 vfs_cache_pressure 라는 값을 크게 잡아, 커널의 cache를 빨리 날려줄 수 있도록 한다. linux에서는 어플에서 처리한 남는 메모리를 바로 free되지 않고 buffer cache에 남게 한다. 이를 이용하면 free memory를 더 확보할 수 있다. 하지만 위험성이 존재하니, 테스트가 필요하다.

 


4. swap in, swap out 확인하는 방법

sar 명령어를 이용하면 메모리 상태를 확인할 수 있다. 

]# sar -r -s 11:41:00
Linux 2.6.9-78.ELsmp        

11시 41분 kbmemfree kbmemused  %memused kbbuffers  kbcached kbswpfree kbswpused  %swpused  kbswpcad
11시 42분   5932304  10700956     64.33    358820   1087040   2096280       192      0.01         0
Average:    5932304  10700956     64.33    358820   1087040   2096280       192      0.01         0

 

sar 명령어의 –B 파라미터는 swapping 통계를 낸다.

]# sar -B 2 5
Linux 2.6.9-78.ELsmp

11시 41분 28초  pgpgin/s pgpgout/s   fault/s  majflt/s
11시 41분 30초      2.04     75.51     21.43      0.00
11시 41분 32초      0.00      0.00    359.49      0.00
11시 41분 34초      0.00    258.46     19.49      0.00

 

5. 이슈

jvm 영역에서 사용된 메모리는 언제나 swap 영역으로 이동될 수 있다. 
jvm 에서 nio를 사용하는 경우 (예, DirectBuffer) 에는 리눅스 운영체제가 언제든지 swap 영역으로 이동할 수 있다. 이를 방지하기 위해서는 mlock/mlockall 시스템 콜을 이용해서 특정 virtual address를 ram 에 묶어 둘 수 있게 한다. 

mlock을 쓰는 방식이 cassandra 0.6.5 에서 추가되었다.

 

마치며..

리눅스의 swap 메모리를 이해할 수 있었다. jvm을 사용하면서 나타날 수 있는 swap 메모리 이슈에 대해서 쉽게 처리할 수 있도록 공부하자.

cassandra의 swap 이슈 에 대한 분석을 좀 더 이해하려고 한다.

'c or linux' 카테고리의 다른 글

Ubuntu의 SMART 프로그램  (0) 2012.01.09
TOP 을 통해 본 리눅스 메모리  (0) 2012.01.06
Swap 메모리  (2) 2012.01.05
리눅스 운영체제의32bit 또는 64bit 여부 확인  (0) 2011.12.30
ubuntu 패스워드 변경  (0) 2011.11.23
Ubuntu 11.04 패스워드 분실시 처리  (0) 2011.11.15
Posted by 김용환 '김용환'
TAG C, 리눅스

 

프로세싱(Processing) 개발 툴을 분석하고 나면,  아두이노 개발 툴 소스 분석은 더 쉽다. 
아두이노 개발 툴은 프로세싱 개발 툴 소스 depedency가 있거나 복사된 소스들이 많다.  (정확히 역사는 어떻게 되었는지는 모르지만..^^;)

1. 소스를 다운받는다.

http://www.arduino.cc/en/Main/software  페이지에서 소스를 다운받는다.

 

2. 이클립스 프로젝트 환경 구축

이클립스 프로젝트를 하나 생성하고 다운받은 소스를 복사한다. 아두이노 개발 툴 안에 이클립스 설정이 파일이 있다.

 

아두이노 개발 툴의 build path를 살펴보면, processing-core를 참조하고 있다. (processing.core 패키지를 참조하고 있다.)

 

프로세싱 소스는 아래 위치에서 git로 다운받는다.

http://code.google.com/p/processing/source/checkout

 

프로세싱 코드는 2.0으로 다운받으면, processing.app.RunnerListener 인터페이스를 모두 상속해서 구현하지 않았다고 아두이노 개발 툴 소스의 Editor 클래스 컴파일 에러가 난다. API 구현해주면 깨끗하게 컴파일 완료된다.

public class Editor extends JFrame implements RunnerListener {

…..


@Override
public void startIndeterminate() {
    // TODO Auto-generated method stub
   
}


@Override
public void stopIndeterminate() {
    // TODO Auto-generated method stub
   
}


@Override
public void statusHalt() {
    // TODO Auto-generated method stub
   
}


@Override
public boolean isHalted() {
    // TODO Auto-generated method stub
    return false;
}

 

컴파일 완료된 상태

<아두이노 소스>

 

빌드 연동

 

프로세싱 소스 (core/src 디렉토리의 소스만 잘 빌드되면 됨)

 

3. 소스 디렉토리 확인

UI 부분은 프로세싱과 거의 동일하다.

 

디버그 관련 패키지가 들어가 있다.  컴파일도 하고 실행했을 때 output 처리하는 것들. arduino 보드에 올리는 클래스들이 담겨 있다.

 

프로세싱 개발 툴은 java 기반이지만, 아두이노 개발 툴은 자바 기반 언어대신 C 언어의 특성을 가지고 있다.  (그래서 antlr는 사용할 필요가 없다.)
그러나 화면에 출력되는 문법에 맞는 색상을 칠해주는 패키지이다.

 

이 외. 운영체제(플랫폼)에 맞는 다양한 작업 패키지들이 있다. 여기도 프로세싱 개발 툴처럼  jna가 쓰이고 있다.

processing.app.linux, processing.app.windows, processing.app.macosx


4. 빌드

빌드는 build 디렉토리에 있는 build.xml를 가지고 ant 컴파일 하면 된다.

Buildfile: G:\workspace\arduino-1.0\build\build.xml
build:
revision-check:
windows-checkos:
subprojects-build:
compile:
....
 [launch4j] Compiling resources
 [launch4j] Linking
 [launch4j] Successfully created G:\workspace\arduino-1.0\build\windows\work\arduino.exe
BUILD SUCCESSFUL
Total time: 44 seconds


 

Posted by 김용환 '김용환'