2015/04/25

Ubuntu 15.04 적극 추천


어제 글(어제 밤에 12시를 넘기는 바람에 날짜는 이 글과 동일함)에서 우분투 15.04를 권장하지 않는 분위기로 글을 올렸는데 VirtualBox가 아니고 iMac에 설치해서 잠깐 사용해 본 결과 우분투 15.04를 적극 추천하지 않을 수 없게 입장이 바뀌었기에 이 글을 별도로 작성한다. 적어도 Intel-Mac 사용자들에게는 강력 추천하고 싶다. 기능이 추가된 것보다는 안정성이 상당히 강화된 것에 높은 점수를 주고 싶다. 우분투 14.04 LTS 보다 더 안정된 느낌이다.

원래는 VirtualBox에만 설치하고 메인 머신은 우분투 14.10으로 1년 정도 더 버텨볼 생각이었다. 그런데, 가상머신 환경이라 느려서 그렇지 뭔가 상당히 안정된 느낌을 주었기에 메인 머신에서 테스트해 봐야겠다는 생각이 들어서 15.04로 하드디스크의 우분투 설치 iso를 이용하여 Clean Install 하였다.

 Nvidia 드라이버 안정성

우선, Nvidia 드라이버가 상당히 안정화 되었다. Nouveau 드라이버도 상당히 개선된 것 같고, 우분투 15.04에서 기본으로 제공하는 Nvidia proprietary driver도 346.59 버전으로 거의 최신 버전이다.

일단 14.10버전까지 오픈 소스 Nouveau 드라이버는 Qt Creator에서 QML 등 OpenGL을 사용하는 애플리케이션에서 화면 잔상이 생겨서 거의 사용할 수 없었는데 깔끔하게 동작한다. 다만,  Virtual Box 우분투 guest 머신에서 3D 가속을 사용할 경우 시스템이 죽는 문제가 발생했다. 이는 이전 버전에서도 흔히 생겼던 문제이고 우분투 문제라기 보다는 Virtual Box 문제인 경우가 많았다. Windows guest는 그럭저럭 잘 돌아간다. 3D 가속만 끄고 사용하면 우분투 게스트도 좀 느리긴 하지만 별 문제는 없다.

우분투 14.10까지는 Nvidia proprietary 드라이버를 Nvidia 홈페이지에서 다운 받아 사용해야 했다. 우분투에 기본 탑재된 드라이버를 사용할 경우 공포의 black screen 문제가 발생했었다. 이제는 기본 탑재된 드라이버를 사용하면 된다는 것이 특히, Intel-Mac 사용자들에게는 기쁜 일이다. 또 한가지 Mac 사용자들에게 반가운 점은 화면 밝기 조절을 매 부팅시마다 해 주었어야 했는데 밝기 변경 상태가 재부팅 후에도 잘 유지된다

System 안정성

우분투 14.10 사용시에는 부팅시마다 colord-sane 데몬 등 crash가 끊이질 않았는데 crash가 없어지니 뭔가로 부터 해방되어 편안한 느낌이 든다. 몇일 더 써 봐야 확실해지긴 하겠지만 우분투를 사용하면서 이렇게 안정된 느낌을 받아 본적이 없을 정도다.

우분투 14.10 설치 후 재부팅시 iMac에서 우분투로 부팅할 수 없었던 문제도 사라졌다. EFI 설정이 잘 보존된다. 다만, 우분투 15.04를 설치한 후 EFI Multi-OS 사용시 부팅 순서를 우분투가 1순위가 되도록 조정한다. 이것은 어쩌면 OS 입장에서 당연한 것인지도 모른다. 방금 설치한 OS로 부팅하도록 할 필요가 있기 때문에... 아무튼 부팅 순서는 우분투로 부팅하고 나서 이전 글의 efibootmgr 사용법을 참고하여 바꿔주면 그만이다.

WIFI 안정성

iMac에서는 우분투에 기본 탑재된 Broadcom proprietary driver를 사용하면 되는데 수동으로 설치해 주어야 하는 문제는 아직 남아있다. 몇일 더 써보아야 확인이 되긴 하겠지만 WIFI도 개선이 된듯하다. 무선공유기에 가끔씩 연결이 안되는 문제가 사라졌고 네트워크 속도도 상당히 빨라진 느낌이다. 오늘이 주말이라 그럴 수도 있기 때문에 좀더 지켜봐야 한다. 참고로, 유선 네트워크 드라이버를 언급하지 않는 이유는 예전부터 별 문제가 없었기 때문이다.


아직 하루도 안써 보고 안정성을 얘기하는 것이 때 이르긴 하지만 문제가 발생하면 이후에 다시 글을 수정할 생각이다.

Ubuntu 15.04 출시 잡담


어젯 밤에 우분투 홈페이지에 접속했는데 우분투 15.04 Vivid Vervet이 안걸려 있어서 오늘 오후에 봤더니 걸려 있더라. KAIST FTP는 미러링이 안되어 있었고 neowiz 사이트는 3~4시간... 너무 느려서 독일 미러링 사이트에서 우분투 설치 iso 이미지 파일을 다운 받았다. 의외로 WIFI 사용하는데 3분 정도 밖에 안걸려서 놀랬다.

우분투 15.04 새로운 점?

뭔가 새로운 것에 대한 기대감 때문에 빨리 설치해 보고 싶었는데 막상 Virtual Box에 설치해 보니 별 감흥이 없다. 뭐 늘 그렇듯이 리눅스는 겉모습이 많이 바뀌는 게 아니니까 큰 기대를 가지면 실망하게 된다. 커널이나 기본 소프트웨어 패키지들이 모두 업그레이드 되는데 바뀐게 없다고 하면 만든 사람들은 얼마나 실망이 클까? Mir나 Unity 8은 1년 후 16.04 LTS에서 기대해야 할 듯... 이번 버전 역시 14.10과 유사하게 가상화나 Cloud Computing 관련 서버 버전 Upgrade 내용이 많아 보인다.

우분투 15.04 데스크탑 버전에서 가장 크게 바뀐 것은 init 프로세스로 Upstart를 버리고 다른 리눅스 배포판과 마찬가지로 systemd를 완전히 채택했다는 점이다. 이 역시 겉으로 드러나지 않기 때문에 일반 데스크탑 사용자들은 달라진 것이 없다고 느낄 듯... 부팅 속도가 좀 빨라질거라는데 가상 머신이라 그런지 큰 차이는 못느끼겠다.

얼마 전에 나온 Kernel 4.0을 우분투 15.04에 넣으려고 했는데 일정상 넣지 못하고 3.19를 넣었단다. 커널 0.98일때 Slackware를 처음 접했던 것 같은데 4.0이라니 감회가 새롭다. 참고로 커널 4.0부터 Kernel live patching이 적용된단다. 리눅스가 Windows에 비해 항상 비교 우위에 있는 점이 커널이나 일부 디바이스 드라이버 설치시를 제외하고는 재부팅할 필요가 거의 없다는 것인데, 서버의 경우에는 이제 기계가 망가지지 않으면 재부팅할 일이 없어지는 것인지 두고 볼 일이다. 토발즈가 4.0보다 4.1에 새로운 기능이 더 추가될 것이라니 이번 우분투 버전으로 업그레이드하기를 권하고 싶지는 않다.


Unity에서 눈에 띄는 새로운 사소한 기능이 하나 있는데 Window title bar에 통합된 메뉴를 고정시킬 수도 있다는 점이다. 역시 리눅스 답게 설정할 수 있는 UI는 없으니 dconf-editor를 사용하거나 아래의 명령으로~!!!
$ gsettings set com.canonical.Unity always-show-menus true

설치 후 소감

Virtual Box에서 EFI 모드로 설치하면 부팅이 안되는 증상이 14.10부터 있었는데 해결되지 않아서 BIOS 모드로 재설치 해야 했다. 더구나 BIOS 모드로 btrfs 파일시스템으로 설치 후, 재부팅해서 잘 돌아가나 싶었는데 Virtual Box에서 창닫기 버튼으로 껐더니 btrfs 파일시스템이 맛이 가서 부팅이 안되고 있다. 이 글을 쓰고 있는 내내 부팅이 안되는 걸로 보아 ext4 파일 시스템으로 재설치해야 할 듯... 블로그에 스크린 샷 좀 넣어 볼랬더니... ㅠ.ㅠ... 또 재설치 후에...ㅠ.ㅠ... 아무튼 이래 가지고는 btrfs를 누구에게 권하겠나 싶다.


그리고, 14.10에서 ibus-gtk 패키지가 누락돼서  ibus-hangul 사용시 발생하던 한글 입력 문제들은 해결되었다. 다만, English로 우분투 설치시에는 이전 글을 참조하여 ibus설정을 해 주어야 한다.

2015/04/05

Syntax Highlighter 설치 및 설정


Syntax Highlighter를 적용하면서 몇 가지 문제가 있었는데 참고삼아 정리한다.

설치

아래는 현재 이 블로그에 Syntax Highlighter를 설치하고 수정한 내용이다. 구글 blogger 뿐만 아니라 다른 블로그에도 아래 내용을 Copy & Paste로 HTML 페이지의 </head> tag 앞 줄에 붙여 넣기하면 Syntax Highlighter를 바로 사용할 수 있다.

일단, 사용하지 않는 Brush 파일들은 제거했다. 즉, bash, cpp, css, diff, js, java, text, python, sql, xml 등의 Brush 들만 사용할 수 있다. 그리고, Django 테마(shThemeDjango.css)를 약간 수정하여 사용하고 있으며, toolbar는 제거하였다.
<!-- Syntax Highlighter Additions START -->
<link href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css" rel="stylesheet" type="text/css" />
<!-- Themes: shThemeDefault.css, shThemeDjango.css, shThemeEclipse.css, shThemeMidnight.css, shThemeRDark.css -->
<link href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDjango.css" rel="stylesheet" type="text/css" />

<style type="text/css">
.syntaxhighlighter a,
.syntaxhighlighter div,
.syntaxhighlighter code,
.syntaxhighlighter table,
.syntaxhighlighter table td,
.syntaxhighlighter table tr,
.syntaxhighlighter table tbody,
.syntaxhighlighter table thead,
.syntaxhighlighter table caption,
.syntaxhighlighter textarea {
  font-size: 8pt !important;
}
.syntaxhighlighter {
  -webkit-text-size-adjust: none !important;
  padding: 1px !important;
}
</style>

<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript" />
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js" type="text/javascript" />
<!-- Brushes: bash, cpp, css, diff, js, java, text, python, sql, xml -->
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushBash.js" type="text/javascript" />
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js" type="text/javascript" />
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js" type="text/javascript" />
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushDiff.js" type="text/javascript" />
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js" type="text/javascript" />
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js" type="text/javascript" />
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPlain.js" type="text/javascript" />
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js" type="text/javascript" />
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js" type="text/javascript" />
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js" type="text/javascript" />
 
<script language="javascript" type="text/javascript">
  SyntaxHighlighter.config.bloggerMode = true;
  SyntaxHighlighter.defaults['toolbar'] = false;
  SyntaxHighlighter.all();
</script>
<!-- Syntax Highlighter Additions END -->

구글 Blogger에서의 제약사항

우선, 블로그에 올릴 새 글을 작성해서 publish하기 전에 preview 상태에서는 Syntax Highlighter가 적용되지 않는다. 내용을 수정하려면 일단 publish하고 나서 수정해야 한다.

또 한가지는, iPhone 등 mobile page view에서도 Syntax Highligter가 적용되지 않는다. 다만, Web 버전 보기(또는 PC 화면 보기)로는 제대로 볼 수 있다.

Firefox 브라우저에서 수직 scrollbar 나타나는 문제

위의 21행에서 padding 설정으로 해결.

Mobile 기기에서 line number와 code의 행 mismatch 문제

위의 17과 20행에서와 같이 font-size와  -webkit-text-size-adjust 설정으로 해결.

2015/04/02

Static Queue 테스트


앞서 만든 static queue가 잘 동작하는지 몇 가지 테스트를 해 보았다. 먼저, 아래와 같이 queue에 저장할 간단한 데이터 구조를 만들었다.
struct DataItem
{
    DataItem(int key = 0, double value = 0) : m_key(key), m_value(value) {};
    void print() const
    {
        std::cout << "key=" << m_key << ", value=" << m_value << std::endl;
    }
private:
    int m_key;
    double m_value;
};

typedef StaticQueue<DataItem> StaticDataQueue;
그리고, 최대 용량 10개 짜리 dataQue를 만들어서 enqueue와 dequeue 테스트...
//
    StaticDataQueue dataQue(10);
    for(size_t i = 0; i < 100; ++i) {
#if __cplusplus >= 201103L
        dataQue.enqueue(DataItem(i, 0.1 * i)); // call move semantics(-std=c++11)
#else
        dataQue.enqueue(DataItem(i, 10 * i)); // call copy semantics
        //dataQue.enqueue(new DataItem(i, 10 * i)); // OK~!
#endif
        if(i >= dataQue.capacity() - 1 && !dataQue.isEmpty()) {
            DataItem dq_item = dataQue.dequeue();
            std::cout << "Dequeue: ";
            dq_item.print();
        }
    }
    dataQue.print();

Constructor와 Operator 테스트...
//
    dataQue[3] = DataItem(3, 333);

    StaticDataQueue qtmp1(dataQue), qtmp2(100);
    std::cout << "\n<< qtmp1 >>\n";
    qtmp1.print();
    std::cout << "\n<< qtmp2 >>\n";
    qtmp2.print();
 
    qtmp2 = qtmp1;
    std::cout << "\n<< qtmp2 >>\n";
    qtmp2.print();

#if __cplusplus >= 201103L
    StaticDataQueue qtmp3(std::move(qtmp2));
    std::cout << "\n<< qtmp2 >>\n";
    qtmp2.print();
    std::cout << "\n<< qtmp3 >>\n";
    qtmp3.print();
#endif

그럭저럭 잘 동작한다. 위에서 dataQue[3]와 같이 컨테이너의 데이터를 수정하는 것도 바람직하지는 않지만 가능하다. 여기선 단지 index operator를 테스트한 것이다. 메모리 누수도 없고~!

2015/04/01

Static Queue


늙어도 심심삼아 코딩 할 수 있도록 소시적 배운 C++의 기억을 회복할 겸  C++ STL deque을 써서 static queue를 만들어 보았다. 임의의 data structure에 대한 pointer 들을 저장하되 정해진 용량까지만 저장한다. Queue size는 가변적이다. enqueue를 시작하면 정해진 용량까지만 채워지고 그 용량을 넘어서면 과거 데이터부터 자동 삭제된다. 또, dequeue할 때마다 size는 하나씩 감소한다. 즉, size는 0 ~ capacity 내에서 유동적이다.

실제 이 static queue를 써먹을 것인지는 중요하지 않다. 여기서는 C++ Class Constructor 기본 개념과 pointer에 대해 빨리 적응하고, 덤으로 C++11에 추가된 move constructor 등에 대해서도 알아 보는데 의의가 있다.

#include <iostream>
#include <deque>

template<typename _Tp>
class StaticQueue
{
public:
    typedef typename std::deque<_Tp*> _Tp_Data;
    typedef typename _Tp_Data::iterator iterator;
    typedef typename _Tp_Data::const_iterator const_iterator;

    // default constructor
    explicit StaticQueue(size_t capa=100) :
        m_size(0), m_capacity(capa)
    {
        m_dequeue_item = new _Tp;
        m_data = new _Tp_Data;
    }

    // destructor
    ~StaticQueue() { destroy(); }

    // copy constructor
    StaticQueue(const StaticQueue& rhs) { copyFrom(rhs); }

    // copy assignment operator
    StaticQueue& operator=(const StaticQueue& rhs)
    {
        if(this!=&rhs) {
            destroy();
            copyFrom(rhs);
        }
        return *this;
    }

#if __cplusplus >= 201103L
    // move constructor: -std=c++11
    StaticQueue(StaticQueue&& rhs) { moveFrom(rhs); }

    // move assignment operator: -std=c++11
    StaticQueue& operator=(StaticQueue&& rhs)
    {
        if(this!=&rhs) {
            destroy();
            moveFrom(rhs);
        }
        return *this;
    }
#endif
   
    // index operator
    const _Tp& operator[](size_t index) const { return *m_data->at(index); }
    _Tp& operator[](size_t index) { return *m_data->at(index); }

    // getters
    size_t size() const { return m_size; }
    size_t capacity() const { return m_capacity; }
    _Tp_Data* data() const { return m_data; }

    // setters
    void setCapacity(size_t size) { m_capacity = size; }

    void enqueue(const _Tp& item);
    void enqueue(_Tp* item);
#if __cplusplus >= 201103L
    // rvalue reference parameter: -std=c++11
    void enqueue(_Tp&& item);
#endif
    const _Tp& dequeue();
    bool isEmpty() const { return !m_size; }

    void print() const;

private:
    void popFront();
    void copyFrom(const StaticQueue& rhs);
    void moveFrom(StaticQueue& rhs);
    void destroy();

    size_t m_size;       // Current queue size
    size_t m_capacity;   // Maximum queue size
    _Tp* m_dequeue_item; // Storage for a dequeued item
    _Tp_Data* m_data;    // Queue container for storing FIFO data
};


template<typename _Tp>
inline void StaticQueue<_Tp>::enqueue(const _Tp& item)
{
    m_data->push_back(new _Tp(item));

    if(++m_size > m_capacity) {
        popFront();
        m_size = m_capacity;
    }
}

template<typename _Tp>
inline void StaticQueue<_Tp>::enqueue(_Tp* item)
{
    m_data->push_back(item);

    if(++m_size > m_capacity) {
        popFront();
        m_size = m_capacity;
    }
}

#if __cplusplus >= 201103L
template<typename _Tp>
inline void StaticQueue<_Tp>::enqueue(_Tp&& item)
{
    m_data->push_back(new _Tp(item));

    if(++m_size > m_capacity) {
        popFront();
        m_size = m_capacity;
    }
}
#endif

template<typename _Tp>
inline const _Tp& StaticQueue<_Tp>::dequeue()
{
    // What if undeflow condition(m_size==0)?
    if(m_size) {
        *m_dequeue_item = *m_data->front();
        popFront();
        --m_size;
    }

    return *m_dequeue_item;
}

template<typename _Tp>
inline void StaticQueue<_Tp>::print() const
{
    std::cout << "\nQueue size/capacity: " << size() << "/" << capacity() << std::endl;

    if(!isEmpty()) {
        int c = 0;
        for(const_iterator i=m_data->begin(); i != m_data->end(); ++i) {
            std::cout << c++ << ": ";
            (*i)->print();
        }
    }
}

template<typename _Tp>
inline void StaticQueue<_Tp>::popFront()
{
    delete m_data->front();
    m_data->pop_front();
}

template<typename _Tp>
inline void StaticQueue<_Tp>::copyFrom(const StaticQueue<_Tp>& rhs)
{
    m_size = rhs.m_size;
    m_capacity = rhs.m_capacity;

    m_dequeue_item = new _Tp(*rhs.m_dequeue_item);

    m_data = new _Tp_Data;
    for(size_t i=0; i < rhs.m_size; ++i) {
        _Tp* item = new _Tp(rhs[i]);
        m_data->push_back(item);
    }
}

template<typename _Tp>
inline void StaticQueue<_Tp>::moveFrom(StaticQueue<_Tp>& rhs)
{
    m_size = rhs.m_size;
    m_capacity = rhs.m_capacity;
    m_dequeue_item = rhs.m_dequeue_item;
    m_data = rhs.m_data;

    rhs.m_size = 0;
    rhs.m_capacity = 0;
    rhs.m_dequeue_item = 0;
    rhs.m_data = 0;        
}

template<typename _Tp>
inline void StaticQueue<_Tp>::destroy()
{
    if(m_dequeue_item) delete m_dequeue_item;
    m_dequeue_item = 0;

    if(!isEmpty()) {
        for(iterator i=m_data->begin(); i != m_data->end();) {
            delete *i;
            i = m_data->erase(i);
        }
    }

    if(m_data) delete m_data;
    m_data = 0;
}


참고 사항

구글 blogger에 소스 코드 삽입시 Syntax Highlighter를 사용하는 방법은 아래의 사이트 참조.
http://oneqonea.blogspot.kr/2012/04/how-do-i-add-syntax-highlighting-to-my.html