A futex overview and update

Personal Computer/Linux 2023. 3. 27. 22:38 posted by tolkien

 Rusty Russell, Hubertus Franke, Mathew Kirkwood에 의해 2.5.7에 도입된 futex 메커니즘은 사용자 애플리케이션을 위한 빠르고 가벼운 kernel-assisted locking primitive이다. 이것은 매우 빠른 비경합(uncontended) locking 획득 및 해제를 제공한다. futex 상태는 사용자 공간 변수(모든 플랫폼에서 부호 없는 32비트 정수)에 저장된다. atomic operation은 syscall의 오버헤드 없이 경합하지 않는(uncontended) 경우 futex의 상태를 변경하기 위해 사용된다. 경합(contended)하는 경우 커널을 호출하여 작업을 절전 모드로 전환하고 절전 모드를 해제한다.
 futex는 thread programming에서 일반적으로 사용되는 몇 가지 상호 배제(mutual exclusive) 구조의 기초이다. 여기에는 pthread mutex, condvar, semaphore, rwlock 및 장벽이 포함된다. 그들은 지난 몇 년 동안 많은 재건(reconstructive) 수술과 성형(cosmetic) 수술을 겪었고, 이제 그 어느 때보다 더 효율적이고, 더 기능적이며, 더 잘 문서화되었다.

 

Overview

 futex를 직접 사용하는 애플리케이션 개발자는 거의 없지만, 나중에 제시된 개선 사항을 평가하기 위해서는 그 방법에 대한 대략적인 지식이 필요하다. 간단한 예를 들어, futex는 잠금 상태를 저장하고 잠금에서 작업을 차단하기 위한 커널 대기열(waitqueue)을 제공하는 데 사용될 수 있다. syscall 오버헤드를 최소화하려면 잠금이 중단되지 않은 경우 이 상태에서 원자 잠금(atomic lock)을 획득할 수 있어야 한다. 상태는 다음과 같이 정의할 수 있다:


    0. unlocked
    1. locked

 

 locking을 획득하기 위해 atomic test-and-set 명령(예: cmpxchg())을 사용하여 0을 테스트하고 1로 설정할 수 있다. 이 경우, locking thread는 커널을 포함하지 않고 lock을 획득한다(그리고 커널은 이 futex가 존재한다는 것을 알지 못한다). 다음 스레드가 잠금을 획득하려고 할 때 0에 대한 테스트가 실패하고 커널이 관여해야 한다. 그런 다음 blocked thread는 futex_WAIT opcode와 함께 futex() 시스템 호출을 사용하여 futex에서 자체를 절전 모드로 전환하여 futex 상태 변수의 주소를 인수로 전달할 수 있다. 잠금을 해제하기 위해 소유자는 잠금 상태를 0(잠금 해제)으로 변경하고 FUTEX_WAKE opcode를 실행한다. FUTEX_WAKE opcode는 blocked thread를 사용자 공간으로 돌아가 잠금을 획득하려고 시도한다(위에서 설명한 대로). 이것은 최적화의 여지가 많은 명백한 사소한 예이다. Ulrich Drepper의 "futex are tricky"는 여전히 mutex와 같은 locking primitive를 구축하기 위해 futex를 사용하는 것에 대한 좋은 참조 문서이다. 여기에 제시된 예를 개선하기 위한 최적화뿐만 아니라 futex 사용과 관련된 많은 race condition을 언급하고 있다.
 사용자 thread가 futex() 시스템 호출과 함께 커널에 호출할 때 futex 상태의 주소(uaddr), 수행할 opcode(op) 및 다양한 다른 인수를 전달한다. uaddr은 커널이 futex를 참조하는 고유한 "futex_key"를 생성하는 데 사용된다. thread가 FUTEX_WAIT와 같이 futex에서 차단을 요청할 때, "futex_q"가 생성되고 "futex_queues" 해시 테이블에 queuing된다. futex에서 차단된 모든 작업에 대해 하나의 futex_q가 존재하며, 많은 futex당 futex_q가 존재할 수 있다. 여러 개의 futex_key가 동일한 큐에 해시하기 때문에 futex_queue 자체("futex_q's"가 아닌 해시 테이블 목록)는 futex 간에 공유된다. 이러한 관계는 아래에 설명되어 있다:

 대부분의 경우 사용자 공간 상태 변수를 사용하는 방법을 정의하는 정책은 없다. 응용 프로그램(또는 glibc와 같은 라이브러리)은 이 값을 사용하여 구현되는 locking 구조의 상태를 정의합니다. 이것은 부울 변수만큼 간단할 수 있지만(위의 예에서처럼) 최적화된 구현과 다른 locking 메커니즘은 더 복잡한 상태 값을 필요로 한다.
 커널은 간단한 FUTEX_WAIT 및 FUTEX_WAKE 작업 외에도 잠금 구조의 상태에 대한 지식이 사용자 공간에서 가질 수 있는 것보다 더 많은 지식을 필요로 하는 priority inheritance(PI) 체인과 강력한 목록을 관리한다. PI 및 강력한 futex는 상태 변수와 관련된 사용자 정의 정책 규칙의 예외이다. 그들의 상태는 mutex의 잠긴 상태뿐만 아니라 소유자의 신원과 웨이터의 유무에 따라 달라진다. 이와 같이 futex 값은 소유자의 스레드 식별자(TID)와 보류 중인 소유자를 나타내는 비트로 정의된다. 이 정책을 사용하면 사용자 공간 atomic operation을 통해 중단되지 않은 경우 커널 호출을 피할 수 있다.

 

개선 사항

 futex는 2.5.7에 처음 등장한 이후 소수의 개발자들로부터 수많은 개선을 보았다. 일부 주목할 만한 개선 사항에는 실시간 작업에 대한 우선 순위 기반 wakeup(Pierre Peifer)과 강력한 PI futex(Ingo Molnar 및 Thomas Gleixner)가 포함된다. 이러한 후자의 기능은 한동안 사용되어 왔으며 커널 메일링 목록에 대한 훌륭한 토론뿐만 아니라 LWN.net 에서도 적절하게 다루어졌다. 저자의 futex에 대한 시도는 2년반전 여기서 시작되었다. 희귀한 corner case와 race condition을 해결하기 위한 몇 가지 수정 사항 외에도, futex 코드는 이전의 기여 이후로 몇 가지 기능과 성능 향상을 보았다.
 futex 오버헤드를 줄이기 위해 상당한 노력을 기울였다. Eric Dumaze은 PTHREAD_PROCESS_PRIVATE pthread mutex에 대한 최적화로 private futex를 도입했다. private futex는 동일한 프로세스의 thread에서만 사용할 수 있다. 이들은 단순히 가상 주소로 서로 구별할 수 있는 반면, shared futex는 각 프로세스에서 서로 다른 가상 주소를 가지고 있어 커널이 고유한 식별을 위해 물리적 주소를 검색해야 한다. 이 최적화를 통해 private futex에 mmap_sem semaphore를 사용할 필요가 없으므로 시스템 전체의 경합이 줄어든다. 또한 private futex의 reference counting에 사용되는 atomic operation을 제거하여 SMP 머신에서 cache-line 바운스가 줄어든다. Glibc는 이제 기본적으로 private futex를 사용한다.
 Peter Ziljstra는 빠른 경로에서는 get_user_pages_fast()를 사용하고, (일반적인 상황에서는) get_user_pages()를 사용하며, 느린 경로 주변에서만 mmap_sem lock을 사용하도록 강하게 푸시함으로써 futex의 mmap_sem 의존성을 더욱 줄였다(2008년 9월). 이러한 변경은 kernel/futex.c에서 가상 메모리 관련 로직의 대부분을 제거하여 코드를 상당히 단순화하는 추가적인 이점이 있었다. 사용자 공간 주소에 의존하기 때문에 futex는 몇 가지 가능한 fault point을 부담한다. mmap_sem을 사용하는한, get_user()를 호출하기 전에 해제해야 했기 때문에 장애 로직이 복잡해졌다. mmap_sem 사용이 줄면서 작성자는 장애 로직을 크게 단순화하여(2009년 3월) 훨씬 더 읽기 쉬운 코드를 생성했다.
 bitset conditional wakeup은 glibc에서 최적화된 rwlock 구현을 가능하게 하기 위해 Thomas Gleixner(2008년 2월)에 의해 추가되었다. FUTEX_WAIT_BITSET 및 FUTEX_WAKE_BITSET을 사용하면 대기 시간에 동일한 bitset(또는 FUTEX_BITSET_MATCH_ANY와 같은 수퍼 세트)를 지정한 작업으로 wake up task를 제한하는 bitmask를 지정할 수 있다.
 PI futex의 도입 이후, pthread_cond_broadcast()의 glibc condvar 구현은 PI futex로의 대기열을 위한 지원이 부족하기 때문에 FUTEX_REQUEUE의 이점을 활용하지 않고 모든 대기자를 깨울 수밖에 없었다. 이것은 모든 waiter들이 사용자 공간으로 돌아가 lock을 얻기 위한 다툼을 벌이기 때문에 웨이크업 스톰(wakeup storm)이 발생한다. 또한 우선 순위가 가장 높은 작업이 먼저 잠금을 획득하는지 확인하지 못한다. 최근 커널(2.6.31-rt* 및 2.6.32-rc*)에는 이제 작성자의 FUTEX_CMP_REQUEUE가 추가되었다. PI 패치(2009년 4월)는 비PI futex에서 PI futex로 waiter를 대기시키기 위한 커널측 지원을 제공한다. Dinakar Guniguntala의 작업에서 glibc 패치를 통해 실시간 애플리케이션은 곧 guaranteed wakeup order와 더 적은 overall wake-up으로 pthread conditional variable을 사용할 수 있게 될 것이다.

 

자 이제는 뭐죠?

 현재 구현된 kernel/mutex.c를 뒤로 하고, futex 개발자들은 다음 항목들을 고려하고 있다. (다음 단계에 처리할 항목을 담은 문서가 아직 나와 있지 않다.)

man page: 현재 man 페이지에는 새로운 futex 작업의 일부가 포함되어 있지 않다. 이들은 futex의 값에 대한 정책을 제안하고 있으며, 이로 인해 futex 사용에 대한 혼란이 발생하고 있다. 무엇보다도, 사용자 공간 futex() 정의가 /usr/include/linux/futex.h에서 제거되어 man 페이지가 불완전할 뿐만 아니라 부정확해졌다. futex 사용자는 syscall 인터페이스를 직접 사용해야 한다.

adaptive futex: futex의 스케줄링 오버헤드 중 일부는 커널에서 잠들기 전에 적절한 양의 spinning으로 줄일 수 있다. 그러나, futex가 그들의 상태를 사용자 공간에 노출시키기 때문에, 이 spinning은 현재 glibc의 adaptive mutex에서 수행되는 것처럼 사용자 공간에서도 수행될 수 있으며, 소유자가 실행 중인지 여부에 대한 지식이 없어도 spinning은 단순한 최대 재시도 루프로 감소된다.

interruptible futex: 대규모 독점 소프트웨어 프로젝트의 interrupt blocking lock operation에 관심이 있다. 현재 Futex 작업은 signal 발생 시 -EINTR을 사용자 공간으로 되돌리는 대신 자체적으로 재시작된다. futex는 FUTEX_INTRUSTIBLE로 플래그가 지정될 수 있으며, signal발생으로 인한 wakeup시 이 플래그는 시스템 호출을 다시 시작해야 하는지 또는 -ECANCELED를 사용자 공간으로 반환해야 하는지 결정한다. 이러한 기능을 pthread lock primitive로 공개하면 pthread 라이브러리에 대한 non-POSIX compliant 변경이 수반되지만 이는 전례가 없는 것은 아니다.

scalability enhancement: LKML은 NUMA에 최적화된 해시 테이블뿐만 아니라 비공개 해시 테이블에 대해서도 논의되어 왔다. futex 해시 테이블은 모든 프로세스에서 공유되며 특히 대규모 시스템에서 실제 오버헤드로 이어질 수 있는 spinlock에 의해 보호된다. 이 오버헤드는 시스템이 NUMA 노드에서 파티셔닝되거나 private futex를 단독으로 사용하는 프로세스에 대해서는 적용되지 않는다.

futex test suite: 작성자가 futex 기능을 검증하기 위해 전체 테스트 제품군에 대한 요구 사항 목록을 작성하고 있다. 이 test suite는 향후 개발을 위한 regression suite 역할을 할 것이다. futex로 가능한 많은 corner case와 misuse case는 test suite를 복잡하게 만들고 설계에 문제를 제기한다.

 

Acknowledgement

나는 John Stultz, Will Schmidt, Paul McKenney, Nivedita Singhvi, 그리고 물론 Jon Corbet에게 감사를 표하고 싶다. 그의 리뷰는 이 기사를 그렇지 않았을 때보다 훨씬 더 읽기 쉽고 완전하게 만들었다.

AutoValue

Personal Computer/Linux 2020. 3. 8. 19:37 posted by tolkien

facebook을 보다가 AutoValue Cursor에서 bug patch를 했다는 아는 사람의 글을 보고,

뭔가 하고 시간을 내서 찾아봤다.

java에서 상수와 같은 값을 Static class로 선언해 쓰는 경우, 그에 따른 코드 작성하는 부담을 덜어주는 tool이다.

android에서는 gradle에 추가해서 쓰면 된다고 한다.

 

그에 대한 자세한 설명은 다른 분들이 적어놨으므로 link만 인용한다.

[Android] @AutoValue 에 대하여.

[Java] Autovalue 라이브러리 사용하기

 

github에 있는 google의 설명 및 code

AutoValue에 대한 presentation

 

 

Bixby's hello world (3)

Personal Computer/Linux 2020. 1. 1. 00:46 posted by tolkien

오늘은 입력을 받아서 처리하도록 바꾸어보자.

 say "hello"라고 하면 Bixby는 HELLO, WORLD 라고 답을 하고,

 say "foo"라고 하면 Bixby는 FOO, BAR라고 답을 한다.

( Bixby Studio를 7.8.1-r19x.13460로 upgrade하면 나오는 warning에 대한 처리.

더보기

그전에 Bixby Studio를 7.8.1-r19x.13460로 upgrade하면 이전에 있는 예제 code에서 warning이 나온다.
나오는 위치는 capsule.bxb로 아래와 같은 경고이다.

Line 8:3DEPRECATED: `runtime-flags` is deprecated, move to `runtime-version`
[This deprecation will prevent new submissions in 20A] [deprecation 6797]View Deprecation Guide

그러면 capsule.bxb에 있는 runtime-flags { ... } 부분을 지우고 아래 code로 대체하면 그 경고는 사라진다.

  runtime-version (2) {
    overrides {
      concepts-inherit-super-type-features (true)
    }

)

 

먼저 helloWorld.js에서 입력을 받아서 처리하도록 해보자. 함수를 다음과 같이 바꾼다.

module.exports.function = function helloWorld (what) {
  if (what == "foo")
    return "foo, bar"
  return "hello, world"
 }

그러면 Bixby Studio는 바로 아래와 같은 경고를 내보낸다.

there is a warning:
The parameters [what] defined in the function 'null' are not listed in the 'accepted-inputs' []

accepted-inputs에 [what] parameter가 없다. accepted-input은 어디에 있는 것인지...

stack overflow나 bixby developer center에서 찾아보면 endpoints.bxb에서 사용하는 keyword.

즉, what이라는 변수를 Bixby에서 처리할 수 있도록 pipeline을 만들어 주어야 할 것같습니다.

 

먼저, what을 instance로 하는 hello type을  models/concepts/hello.model.bxb 에 만들어 준다.
 ( New -> Model -> template:text, name: models/concepts/hello.model.bxb )

 

그리고, action doHelloWorld에 input parameter가 있다는 것을 알려준다.

 아래 내용을 action(doHelloWorld) 안에 넣는다.

  collect {
    input (what) {
      type (hello)
      min (Required)
      max (One)
    }
  }

그리고, doHelloWorld action과 javascript을 연결하는 endpoint에 accepted-input keyword를 써서 입력이 있음을 알려준다. action-endpoint (doHelloWorld) 안에 한줄 추가

      accepted-inputs (what)

여기까지 하면 warning은 사라지지만, Bixby emulator를 실행시켜보면 뭐라고 말하던 HELLO, WORLD만 외친다.

training에 say "foo"를 학습시켜야 한다. resources/en-US/training에 가서 click하면 학습된 say it이라는 문장이 보인다. 여기서 it을 hello type의 input이라고 알려주어야 한다. 아래와 같이 수정하자.

Save한 다음에 "Compile NL Model"을 click해주면 된다.

Bixby Emulator를 띄워서 say foo라고 치면 "foo, bar"라고 답할 것이다.

여기까지 내용은 제 개인 github에 올라가 있습니다.

 

마지막으로, Bixby가 이 일련의 과정을 어떻게 처리하는지 제가 이해한 바는 다음과 같습니다.

단말에서 say "foo"라고 하면

 1. Bixby는 이 말을 say + parameter:foo로 분해해서
 2. resources/en-US/training에 있는 NL Model에 넣는다.
 3. NL Model에서 say + parameter pattern을 찾으면 출력이 text:world이다.
 4. 출력이 text:world인 action인 doHelloWorld.model.bxb를 찾고,
 5. action-endpoint(doHelloWorld)에서 helloWorld.js를 얻은 다음
 6. helloWorld(parameter:foo)를 호출하여 return값으로 text:"foo, bar"를 얻는다.
 7. 출력은 en-US/dialogs/helloVoice.dialog.bxb내 dialog(Result)에서 처리하는데,
 8. text:"foo, bar"이면 "foo, bar"라고 소리를 낸다.

Bixby's hello world (2)

Personal Computer/Linux 2019. 12. 17. 23:02 posted by tolkien

지난번에 이어 오늘은 Bixby로 하여금 말을 하게 해보자.

 

아직 result-view로 output을 design하는 것을 잘 알지 못하겠고,

Dialog를 써서 소리를 내는 것만 할 수 있을 것같다. (Dialog 재정의 하기)

Dialog event중에서 Result에 대한 dialog를 재정의해서 출력시 소리가 나오게 한다.

 

1. resources/en-US/dialogs/helloVoice.dialog.bxb

 * resources/en-US/dialogs에서 오른쪽 click -> New... -> Dialog 선택한 다음 helloVoice를 생성하고 아래 내용으로 채운다.

dialog (Result) {
  match: world (txt) {
    from-output: doHelloWorld ()
  }

  if (txt == 'hello, world') {
    template("HELLO, WORLD") {
      speech ("hello, world")
    }
  } else-if (txt == 'foo, bar') {
    template ("FOO, BAR") {
      speech ("foo, bar")
    }
  }
}

 * match: {} 부분을 설명하자면 (파악하는데, 시간이 걸렸다.)

    doHelloWorld action에서 나오는 결과값중에서 변수 타입이 world인 txt 변수에 대해서 처리한다.

 * 그리고나서 txt 내용에 따라서 출력할 내용을 정한다.

   speech() 함수를 이용해서 소리내서 말하게 하는데, SSML이라는 문법을 사용한다고 한다.

   (Bixby에서 사용되는 SSML 설명)

 * 참고로 javascript 함수인 HelloWorld()에서 return 값이 "foo, bar"로 return하면 "foo, bar"로 발음한다.

 

예제 파일은 https://github.com/tolkien/playground.helloworld 에서 받을 수 있습니다.

다음할 일 : 입력을 say hello로 받으면 hello, world를, say foo를 받으면 foo, bar를 말하게 하기

Bixby's hello world

Personal Computer/Linux 2019. 12. 10. 02:49 posted by tolkien

컴퓨터 언어를 새로 접하면 항상 해보는 것이 "hello, world" 문자열찍는 예제이다.

빅스비에서 hello, world에 해당되는 것이 capsule-sample-dice, 이른바 주사위 던지기.이다.

 

심지어 Bixby Developer Center에 들어가면 Quick Start Guide로 제시하고 있다.

처음부터 생성하는 것이 아니라 예제를 download받고 그 내용을 설명하는 것으로 되어 있다.

빅스비의 개념을 익히는데, 상당히 힘들뿐 아니라 실행도 전혀 빅스비답지 않다.

그래서, 만들어봤다.

 

0. Bixby Studio를 깔고 실행하면 제일 먼저 login 화면이 나온다.

    삼성 Bixby 개발자로 등록하지 않으면 Bixby 맛도 볼 수 없다. 돈 드는 것 아니니, 등록하자.

    여기서 사용한 Bixby Studio Version은 7.8.0-r19w.13177 (2019/12/10일 기준) 이다.

 

1. Capsule 만들기. 빅스비에서는 실행파일 == Capsule이다.

- File메뉴에서 New Capsule 선택하고, Capsule ID는 playground.helloworld .

* 참고로 playground.라는 prefix를 주지 않으면 Bixby IDE에서 생성하지 않는다. 그리고, Capsule ID는 영어 소문자로 시작해야 한다. 이런저런 이름에 대한 제한은 Capsule 생성 dialog에 있는 link를 찍어서 내용을 확인할 것.

 

생성하면 뭔가 기본 파일들을 만들어 주는데, error 3개, warning 7개가 뜬다. 시작부터 난감.

일단 이 error부터 잡으면서 시작하는 것이 정신건강상 좋은 것같다.

 

2. 해당 Capsule을 확장하면 보이는 capsule.bxb 를 열고 아래 내용을 추가한다.

  store-sections{
    section (GamesAndFun)
  }

  store-countries{
   // all
   only{
      allow (KR)
    }
  }

그리고, runtime-flags { .. } 안에 다음을 추가한다.

 // add below for error correction
no-filtering-with-validation
modern-default-view-behavior
use-input-views-for-selection-list-detail

 

3. 그 다음으로 resource/en-US/capsule-info.bxb 을 열어서 다음을 추가한다.

  dispatch-name (helloworld)
  search-keywords {
    keyword (hello)
  }

그럼 warning 하나 빼고 capsule.bxb에서 나오는 error는 사라진다.

(남은 하나는 icon file이 없다고 징징대는 것인데, 없어도 실행하는데 지장없다.)

 

4. 그리고, resources/en-US/hints.bxb 파일을 열어서 hint(...) 부분을 지우고 다음을 추가.

    hint (ask helloworld to say it)
    hint (ask helloworld to say world)
    hint (ask helloworld to say something)

여기에 좀 지저분한 것이 있는데, 보고 싶으시면

더보기
The current en-US dispatch patterns are the following:

 

"with %dispatch-name% ..."

"in %dispatch-name% ..."

"ask %dispatch-name% ..."

"ask %dispatch-name% for ..."

"ask %dispatch-name% to ..."

 

The current ko-KR dispatch pattern is the following:

 

%dispatch-name% 에서 ...

 

for detail, see https://stackoverflow.com/questions/57241026/invoke-specific-action-when-bixby-capsule-launched

 

이제 warning 하나만 남았으니 뭔가 compile해서 실행할 수 있을 것같다.

여기서 왼쪽 하단의 휴대폰 모양 icon을 click하면 Bixby emulator가 뜨는데,

왼쪽에  어떤 글자를 입력한 다음에 "Run NL"을 실행해도 "I didn't understand that"이라는 말만 한다.

그럼 이제 뭔가를 타이핑하거나 말하면 hello, world라는 글자가 출력되게 하자.

 

5. models/concepts/world.model.bxb 생성

 * Bixby에서 Concept은 C나 java에서 변수와 같은 개념이다. 변수가 100개면 Concept 파일이 100개~

 * 왼쪽 helloworld Capsule browser에서

  . models를 click해서 확장시키고

  . concepts 위에서 마우스 오른쪽 click 하면

  . Context Menu가 뜨고, 거기서 New -> Model 선택하면 Dialog가 뜬다.

    여기서 File Type: Model, Template : Text 선택해주고, filename은 world.model.bxb

 

  -> 이러면, world라는 text 변수가 하나 생성되었다.

 

6. code/helloWorld.js 생성

 * 그 다음에는 world라는 text 변수에 "hello, world"를 넣도록 javaScript을 작성하자.

 * helloworld Capsule browser에서

  . code 위에서 마우스 오른쪽 click해서 New -> Action JavaScript 선택

  . 파일명은 code/helloWorld.js 으로 만들어 주고, 아래 내용으로 바꾸어 넣자

module.exports.function = function helloWorld () {
  return "hello, world"
}

 

7. models/actions/doHelloWorldᅟ.model.bxb 생성

 * 이제 doHelloWorld라는 ᅟAction을 생성한다. 일종의 trigger라고 생각하면 된다.

 * helloworld Capsule browser에서

  . models -> concepts 위에서 마우스 오른쪽 click해서 New -> Model 선택

  . File Type: Model, Template : Action, filename은 doHelloWorld.model.bxb

  . 그리고, 아래 내용으로 바꾸어 넣자

action (doHelloWorld) {

  output (world)
  type (Calculation)
}

 

8. resources/base/views/helloWorld.view.bxb 생성

 * 출력 형태를 결정하는 것인데, 그냥 빈파일로 냅두자. (생성하지 않아도 됨)

 * helloworld Capsule browser에서

  . resources -> base -> views 위에서 마우스 오른쪽 click해서 -> New -> View

 

 

9. endpoints 설정하기.

 * endpoint란 input -> action -> output 을 연결해주는 역활은 한다.

 * resources/base/endpoints.bxb 의 내용을 아래 내용으로 바꾼다. 입력이 없으므로 따로 정의하지 않는다.

endpoints {
  // action과 그에 맞는 자바스크립트를 매핑
  action-endpoints {
    action-endpoint (doHelloWorld) {
      local-endpoint ("helloWorld.js")
    }
  }
}

 

 

10. 이제 빅스비를 훈련시켜서 hello, world 문자열을 출력하게 하자.

 * resources/en-US/training 열면 다음과 같은 화면이 나온다.

 

"Enter natural language training"이라고 써 있는 곳에 say it 이라고 입력하고 Add를 click하면

GOAL을 입력하라고 나온다. 여기에 정의해두었던 Concept인 world 을 입력하고 저장한다.

그리고, "Compile NL Model"을 click하면 hello, world 문자열을 볼 준비는 다 끝난 것이다.

 

11. 이제 hello, world 예제를 실행해보자.

 * 왼쪽 하단의 휴대폰 Icon을 click에서 emulator를 실행하고,

왼쪽에 say it이라고 입력한 다음에 "Run NL"을 실행하면 hello, world 문자열을 볼 수 있다.

 

마지막으로, 한가지 고백하자면 입력창에 어떤 내용을 넣어도, 어떤 말을 해도 위 화면만 나오게 된다.

왜냐하면 Bixby Emulator에서는 helloWorld Capsule만 동작하고 있고, 입력과 상관없이 무조건 hello, world 를 출력하게 했기 때문이다.

 

예제 파일은 https://github.com/tolkien/playground.helloworld 에서 받을 수 있습니다.

 

개선할 점. hello, world을 음성으로 들을 수 있도록 해보자.

 

opengrok에서 확장자 추가하기

Personal Computer/Linux 2019. 11. 22. 12:52 posted by tolkien

source browser로 opengrok을 쓰고 있습니다.

java, asm, c/c++ 등의 파일을 parsing해서 source code 돌아다니기 편하게 해줍니다.

 

그런데, 가끔 custom한 확장자를 사용하는 code들이 있습니다.

예를 들어 source 일부를 .inc file로 만들어서 include하는...

이런 경우, opengrok는 그냥 text file로 처리합니다.

 

오늘 code를 보다가 drvInit() 함수의 definition이 없어서 찾아보니

그런 파일에 있었네요. 그래서, 조금 googling했습니다. 그랬더니

opengrok.jar내 -A option이 있다고 합니다. 사용법이 조금 까다로운데

 

-A sln:org.opensolaris.opengrok.analysis.plain.PlainAnalyzerFactory

 

C file로 인식하는 것은 아래와 같지 않을까 생각하고, option을 넣어서 다시 indexing합니다.

-A inc:org.opensolaris.opengrok.analysis.c.CAnalyzerFactory 

뒤에 있는 명칭은 opengrok source code를 보면 대충 짐작이 됩니다.

https://github.com/oracle/opengrok/tree/master/opengrok-indexer/src/main/java/org/opengrok/indexer/analysis

 

참고 자료 :

- opengrok wiki

- opengrok github

- Re: [opengrok] How to add more file extensions (file types)

- stackoverflow에서 찾은 글

.

1. 제일 먼저 Inbox에 모아보기 설정

 - 여러 email 계정의 inbox를 한곳에 볼 수 있는 것이 편한데, 이건 기본설정이 아니다.

 - 설정방법 : View -> Folders -> Unified 선택

 

2. email 계정 순서

 - 이건 안 바뀐다. 따라서, 자주 보는 것을 먼저 등록할 것.

[samba] windows 7 system error 86

Personal Computer/Linux 2019. 6. 17. 16:59 posted by tolkien

ubuntu 18.04를 판올림한 다음에 이것저것 service가 안되는 것이 몇몇 있어서

그때그때 마다 해결하면서 쓰고 있다.

linux desktop에 samba를 설정해놓고, 회사 노트북에서 이를 당겨 쓰고 있다. 아래와 같이

    Z: drive of windows 7 notebook == /home/tolkien/tmp of linux desktop

작업환경이 linux desktop이다보니 자료던 뭐던 linux desktop에서 찾고 보게 되고,

windows 7 notebook은 email, 또는 m$ office를 이용해서 출력할 때만 쓰게 된다.

(누군 libre office를 써서 linux desktop에서 출력까지 하던데.)

여하튼 이렇게 연결해놓고 쓰고 있었는데, 갑자기 접속이 안되는 것이다.

탐색기로 보면 뭔가 요란하게 나오는데, 결론은 username 하고 password가 틀리다는거다.

 

응? 그래서, 내가 기억하고 있는 id/passwd가 틀렸나보다 생각하고,

linux desktop에서 smbclient를 써서 확인해보면 잘 접속이 된다.

    smbclient -L <linux desktop IP> -U tolkien

혹시나해서 MacBook에서 같은 실험. 잘 접속이 된다.

이건 windows 7이 뭔가 바뀌었다는 얘기. 회사 notebook이다보니 이런저런 이유로 설정이 바뀌어져 있는 경우가 있다.

googling해서 cmd.exe에서 test를 해봤다.

    c:\Users\john> net use L: \\myserver\myshare /u:myuser mypassword

    System error 86 - The specified network password is not correct.

System error 86? 좀 더 확인해보니까, security policy를 바꾸어보라고 한다.

    c:\Users\john> secpol.msc
    #   -> Local Policies
    #    -> Network Security : LAN Manager Authentification level
    #       change it to 'Send NTLMv2 response only. Refuse LM & NTLM'

그런데, 회사에서 설정바꿀 수 없게 lock을 걸었다!

 LAN Manager Authentification level이

 'Send LM & NTLM - use NTLMv2 session security if negotiated' 고정되어 있슴.

 

다행히 누가 댓글로 다른 해결책을 알려줬다. smb.conf 에 아래 한줄 추가

    ntlm auth = true

 

오늘도 이렇게 평화는 지켜졌슴.

maxima 설치하기

Personal Computer/misc 2019. 2. 23. 04:32 posted by tolkien

방송통신대 강의를 듣다보니 wxMaxima라는 tool을 사용한다. Maxima라는 수식을 간단하게 풀어주거나 Graph를 그려주는 program의 wxWidget front-end. 예전에 써봤던 Mathematica의 open source version으로 추측된다. 이걸 macbook에 설치해보니 실행이 제대로 안된다. 그래서, 다른 front-end중에서 이전에 tensorflow때 써먹었던 jupyter가 있길래 여기에 붙여본다고 삽질. (기준은 mac OS X 10.13.6 High Sierra )


1. brew를 통해서 maxima를 설치한다.

brew install maxima

2.   maxima를 실행한 다음에 다음 명령어가 먹으면, jupyter 설치(6번)로 들어간다.

f(x) := sin(x);

3. maxima 동작이 이상하면 이제 source build를 해야 한다. 먼저 sbcl이라는 lisp interpreter를 설치해야 한다.

brew install sbcl

4. 그리고, maxima source를 받아서 build. (mac은 platypus라는 것이 필요하다.)

git clone https://github.com/andrejv/maxima.git

brew install platypus

cd maxima

./bootstrap

make -f macosx/Makefile

5. 그러면 ~/Desktop/Maxima.app 이라는 directory가 생긴다. app을 실행할 것이 아니므로 적당한 곳은 옮기고, 그 안에 있는 실행 shell script을 실행가능한 path로 link 걸어놓는다. maxima를 실행시켜서 잘 동작하는 거 확인. 여기까지 안되면 그냥 windows binary 가져다가 사용할 것.

mv ~/Desktop/Maxima.app ~/Public

ln -s /Users/tolkien/Public/Maxima.app/Contents/Resources/maxima.sh ~/bin/maxima

6. jupyter를 설치해야 한다. 그리고,  ~/.sbclrc를 생성해서 다음과 같은 내용을 추가해주자.

brew install python3 pip3

pip3 install jupyter


MacBook-Air:work tolkien$ cat ~/.sbclrc 

(setf sb-impl::*default-external-format* :utf-8)

7. quicklisp이라는 것도 설치.

curl -O https://beta.quicklisp.org/quicklisp.lisp

sbcl --load quicklisp.lisp

- 여기부터는 lisp intepreter 명령임 -

(quicklisp-quickstart:install)

(ql:system-apropos "vecto")

(ql:quickload "vecto")

(ql:add-to-init-file)

(quit)


8. maxim-jupyter source를 download.

git clone https://github.com/robert-dodier/maxima-jupyter.git

9. build, 중간에 실패하면 10번 참조
cd maxima-jupyter

mkdir -p binary/binary-sbcl

maxima

- 여기부터 maxima 명령임 -

:lisp (load "load-maxima-jupyter.lisp")

:lisp (sb-ext:save-lisp-and-die #P"binary/binary-sbcl/maxima-jupyter-exec" :executable t :toplevel 'maxima-jupyter:kernel-start-exec)

10. 중간에 아래와 같은 message를 내면서 build 실패하면, lisp file을 patch해야 한다.

; /Users/tolkien/.cache/common-lisp/sbcl-1.4.16-macosx-x64/Users/tolkien/quicklisp/dists/quicklisp/software/pzmq-20171019-git/grovel__grovel /Users/tolkien/.cache/common-lisp/sbcl-1.4.16-macosx-x64/Users/tolkien/quicklisp/dists/quicklisp/software/pzmq-20171019-git/grovel__grovel.grovel-tmp.lisp

While evaluating the form starting at line 19, column 0

  of Maxima encountered a Lisp error:


 Couldn't execute "/Users/tolkien/.cache/common-lisp/sbcl-1.4.16-macosx-x64/Users/tolkien/quicklisp/dists/quicklisp/software/pzmq-20171019-git/grovel__grovel": Permission denied


Automatically continuing.

To enable the Lisp debugger set *debugger-hook* to nil.

#P"/Users/tolkien/work/maxima-jupyter/./load-maxima-jupyter.lisp":; 

10.1 patch file.

--- /Users/john/tmp/grovel.lisp 2019-02-23 03:45:12.000000000 +0900

+++ /Users/john/quicklisp//dists/quicklisp/software/cffi_0.20.0/grovel/grovel.lisp 2019-02-23 03:45:04.000000000 +0900

@@ -243,6 +243,7 @@

             (link-executable exe-file (list o-file)))

         (error (e)

           (grovel-error "~a" e)))

+      (apply 'invoke `(#+bsd ,@`("chmod" "755" ,exe-file)))

       (invoke exe-file lisp-file)

       lisp-file)))

11. 무사히 build가 끝나면 다음과 같은 실행파일을 볼 수 있을 것이다. (이제 다 왔다!)

MacBook-Air:maxima-jupyter tolkien$ ls -lh binary/binary-sbcl/

total 196736

-rwxr-xr-x  1 tolkien  staff    84M  2 23 03:46 maxima-jupyter-exec*

12. 이제 jupyter에 maxim kernel을 추가.

python3 ./install-maxima-jupyter.py --exec=`pwd`/binary/binary-sbcl/maxima-jupyter-exec


또는, virtualenv 환경에서 jupyter를 실행한다면 아래처럼 설치위치를 지정해주어야 한다.


python3 ./install-maxima-jupyter.py --prefix=/Users/tolkien/tf --exec=`pwd`/binary/binary-sbcl/maxima-jupyter-exec

13. jupyter를 실행하고, New button을 눌러서 maxima kernel이 있는 것을 확인하면 된다.

jupyter-notebook


참고 site:

  • http://maxima.sourceforge.net - maxima official site
  • http://maxima-online.org  - maxima web front-end
  • https://github.com/andrejv/maxima - maxima GitHub mirror
  • https://github.com/robert-dodier/maxima-jupyter - maxima-jupyter Github
  • https://www.quicklisp.org/beta/ - quicklisp official site


mac OS 10.7.5의 어중간함.

Personal Computer/MacBook 2008 2019. 2. 10. 14:14 posted by tolkien

맥북이 두대가 있는데, 그중 macbook 2008은 지원되는 OS가 mac OS 10.7.5 Lion까지다. 이유는 CPU는 64bit이지만, EFI Bios가 32bit라서... google로 찾아보면 어찌어찌 hack해서 이후 OS를 설치하는 덕후들도 있지만, 솔직히 그냥 평범한 notebook에 hackintosh 설치하는 것과 크게 다를게 없다.


그동안 별 불만없이 2nd PC로 잘 쓰고 있었다. 헌데 open source software 진영에서도 하나둘씩 지원을 멈추더니 google chrome, firefox가 EOL (End Of Life)를 선언하고 이후 web browsing하는 데, 하나둘씩 불편함이 늘어나고 있다. 최근에 문제가 된 것은 SSL 인증 문제. 느린 것을 참겠지만, 아예 접속이 안되니... 아직까지 firefox 마지막 지원 version (48.0.2)으로 internet을 쓸 수 있겠지만, 이것도 언제까지 갈지..


결정적으로 그동안 잘 써왔던, brew에서 10.7.5에 대한 지원을 다음 version부터 하지 않겠다고 하면서 편하게 쓰던 3rd party software도 힘든 상황이 되었다. 그 대안으로 쓸 수 있는 것이 아직까지 지원하고 있는 MacPort와 TigerBrew.


여기서 TigerBrew가 brew의 fork라서 쓰기 편한데, 이건 말그대로 Tiger OS, 즉, PowerPC Mac을 지원하는 project라는 거다. bottle도 전부 ppc binary라서 내가 쓸 때는 항상 build부터 시작한다. 가끔 build error는 덤.


google을 뒤져봐도 macOS 10.7.5를 Apple 지원없이 계속 쓰지 위한 움직임은 보이지 않는다. 68k Mac이나 PPC Mac처럼 사용기간이 오래된 것도 아니고, 충성스런 사용자층이 있는 것도 아닌 것같고. 실사용기와 레트로 사이에 낀 어중간함이 꽤 지속될 것같다.