생각을 깊게하면 좀 더 난이도를 낮출 수 있다!!

요즘 회사서 기존 소스코드를 분석하고 있는데...수백줄이 각종 for 문으로 왔다갔다 하는 부분이 있었다. 이거 뭐이리 복잡하나...싶어서 봤더니. 결국 찾아내고 싶은 값은 하나. 각종 전역변수들을 들락날락 했던 이유는? 관계된 값을 찾을 때, index값을 이용하기 때문이었다.

즉 간단히 말해서는 RDB의 모습이었다는것. 뭐 취지는 좋다. index 기반이니까 배열으로써 바로 접근이 가능하니까. 속도면에서도 그럭저럭 쓸만할테고...메모리량도 적게먹을테고. 그러나... 코드가 너무 지저분하며, 검색시에는 해당 값으로 정렬되어있지않기 때문에 무조건 for문을 이용해서 linear하게 찾을 수 밖에 없다. 게다가 테이블에는 유일한 값이 있는것이 아니라 중복값이 있을 수 있다. 즉 for 문 안에서 1번 조건을 만족 하더라도, 2번조건에 부합되지않으면 마저 돌아야되는것. 이러다보니 소스코드가 좀 너저분하고 분기문이 많아진다.

찾는 값들을 살펴보니...3비트, 2비트 길어봐야 16비트 정도의 값이다. 다 합쳐보면 32비트 미만일 듯 싶다. (찾는 값들은 key값들로 볼 수 있고, 나머지 value 값들도 존재함) 이럴 때 사용할 수 있는건 뭔가? DB에서 사용되는 BITMAP Index 를 사용할 수 있지않을까. 그러면 검색하고 싶은 조건을 한번에 32비트안에 다 집어 넣을 수 있을테고 (SQL문의 where 절이 되겠다.) 총 entry 개수만큼 iteration만 하면 100% 검색이 가능하다.

총 entry는 너무 많다고? 그럴수있다. 지금 내가 참여하고있는 프로젝트는 소형 기지국 Femto cell 쪽 SW인데 여기는 총 8명 user에다가 각 유저당 8개의 entry를 가진다. 그럼 여기선 64개의 iteration을 가지지만 64명의 user를 지원한다면? 128번의 iteration이다. 제법 많아지게 되는것이지. 그럴경우? 그럼 유저당 검색을 별개로 할 수 있도록 partitioning을 하면 되는것. 그럴경우 256명을 지원한다고 해봐야 메모리는 좀 더 잡아먹을 수 있겠지만 (그나마도 dynamic allocation을 활용하면 극도로 효율적인 운영이 가능하다.) 속도는 MAX 8번의 iteration만으로 가능해진다.

코드도 보기 좋아지고, 속도도 빨라지고...이 얼마나 좋을소냐. 제발 생각좀 하자...생각좀...

ps : 뭐 사실...생각의 부재라기보다는...Data Structure에 대해서 깊게 공부하는 사람이 없어서 더 이런 문제가 있는 것 같다. 프로그래밍의 가장 중요한 요소인데 말이지...쩝.

ps2 : 어찌보면...DB의 역정규화와 상당히 동일한 작업이다. storage는 조금 더 쓰는 방향이 될듯. (entry들의 사이즈가 작아서 큰 문제는 없다)

1. CRC 란?

CRC라는게 뭔지는 알아야겠지? 일단 비트 계산이 이용된다. 덧셈연산은 XOR(Exclusive OR)가 사용되며 곱셈연산은 AND연산과 동일하다.

영어 위키는 여기. http://en.wikipedia.org/wiki/Cyclic_redundancy_check 잘 정리 되어있다. 간추리자면, 약자 그대로 모든 비트를 검사하고 그걸 축약시켜서 n bit 길이의 code로 만들어 두면, 나중에 실제 message k bits를 보냈을 때, n bit code 검사만으로도 k bit에 Error 가 있는지 없는지 검사할 수 있다는 것. 계산 방법은 영어 위키 페이지에서 Computation of CRC 챕터에 간단히 잘 나와있다.

자 그럼 내가 이 문서를 쓰는 의의는 뭘까?

웹페이지 검색을 해보면 '그냥 이렇게 계산해~' 정도만 나와있다. CRC 원리를 그대로 sw로 구성하면 매우 비효율적이다. 한 비트씩 shift 해서 연산해야되니까. 수백KB가 되면 그거 다 shift하려면 하세월이지. 그런데 SW예제들을 보면 그냥 Table Lookup 방식을 쓴단말이지. 왜 이렇게 해도 되는지는 잘 나와있지않다. 생각해보자. 원리는 bit shifting을 통해서 해야된다고 나와있는데, 실제 구현은 table lookup. 왜 table lookup을 써도 괜찮은지에 대한 설명을 찾기가 쉽지않다. (물론 아주 어려운건 아니다. 그러니까 내가 찾았지 -_-;;) 그래서 table lookup을 쓸 수 있는 이유를 증명을 통해 보이려고 한다. 사실 증명은 문서로 이미 되어있거든. 지금 쓰는건 단지 그것을 이해하고 쉽게 '한글로' 풀어쓰려는 것일뿐. 그 이상도 그 이하도 아니다.

 

2. CRC 계산 기본

SW 구현을 이해하려면 기본적으로 CRC 계산 수식들에 익숙해져야한다. (CRC가 어떻게 Error Detection을 하고, 제대로 하는것인지에 대한 증명은 패스. 그냥 기본적인 것만 한다.)

CRC 계산을 위해 generator polynomial이 주어지게 되는데 그걸 g(x)라고들 표현한다. (위에 위키 페이지에 보면 잔뜩있는 CRC-8, CRC-16 등등에 사용되는 수식들임) 그리고 입력에 사용되는 k-bit message를 u(x), message에 CRC정보를 덧붙여서 만든 n-bit codeword를 v(x)라고 한다. 그리고, CRC로 붙는 (n-k) bit 내용을 s(x)라고 하자. 요런 관계를 수식으로 표현하면

(1)

    로 표현할 수 있다. 로 나눈 후 나머지가 되는 임의의 다항식이라고 가정하면,

    (2)

      라고 가정이 가능하다. (도 역시 임의의 다항식) 이런 상황이 만족되는 경우, 덧셈연산이 XOR이므로 가 된다. 그러므로 v(x)는 g(x)로 나눠떨어지는 값을 가지게 된다. 즉, Error Detect측에서는 단순히 정해진 g(x)로 나눠서 나머지가 없으면 error가 없는 것이라고 판단하는 것이다.

       

      참쉽죠? ^________^

       

       

      …. 라고 하면 맞으려나? -_-; 사실 수학에 손땐지 오래인 나로써는 쉬워보이면서도 이해하기 어렵더라. 근데 알고보면 별 거 아니다. 솔직히 (1)방정식의 가 어디서 나온건지 궁금해 할 수 있다. (철저히 개인적이다. 뭐…내가 쓰는건데 개인적으로 쓰는거지 ㅡ,.ㅡ) 아까 젤 위에 가정을 할 때 k는 original message의 길이, n은 CRC정보가 첨부된 길이라고 했다. 즉, 항상 n>k 임을 알 수 있다. 요거는 단지 u(x)의 k승수를 v(x)의 n승수로 맞춰주기 위해 곱해주는 것 일뿐~ 뭐 이것만 알면 아래에 SW구현 파트는 이해가 가능하다.

       

      이 챕터를 끝내기 전에 예제를 한번 풀어보자.

      101011 이라는 bit sequence의 CRC값을 계산하자. 이 경우 이다. g(x)의 경우 CRC-16으로 하기로하면 이 된다. 계산하면

      이고 여기에서 s(x)를 계산하면 Figure 3과 같이 된다.

      즉, 101011을 CRC-16을 거치면 0111110100000000101011 이 된다.

       

      3. SW 구현

      위에서 말했다시피 HW 구현은 그냥 CRC 원리 그대로 bit 계산으로 하면 된다고 치자. (물론 더 좋은 방법으로 구현들 할꺼다…하지만 HW는 내 알바 아니니 패스) SW으로 그렇게 구현하려면 무지 비효율적인것도 이미 말했으니…바로 어떤식으로 계산하면 좋을지 수식으로 들어가자.

       

      CRC generator polynominal을 g(x)로 표현하기로 하고 예제로는 CRC-16을 사용한다고 가정하자. u(x)는 message bits를, s(x)는 g(x)로 나눈 나머지를 의미한다고 가정하자. 그러면…

       

       

      으로 표현이 가능하다. 그리고

              

      로 가정한다. 자 이제 한 바이트, 즉 8비트가 밀려들어왔다고 가정하자. 새로운 값이 추가된 meesage를 u'(x) 라고 가정하면,

              

      이다. 새로운 나머지값인 s'(x)는

              

      로 표현 할 수 있다. (R은 나머지값이라는 표현임. 다른 뜻은 없으니 크게 신경쓰지말자~) 자~ 식을 전개해보면

              

       

              

      b(x)와 s(x)를 전개해보면

              

      , i = 0,1, … , 7 로 변환시키면

              

              

      요렇게 된다. g(x)가 이것보다 큰 값이니까 나머지해봐야 그대로 남는 것이고…자, 8비트 추가된 후의 나머지(CRC)값의 방정식이 구해졌다. 살펴보도록 하자.

      일단 의미는 뭘까? 은 8비트 추가가 되기 전에 기존 CRC값의 high-order 8비트값이었다. 그런데 그게 단순히 8비트 right-shift 된 것이지. (x의 승수가 높을수록 low-order bit이다. 위에서 예제로 계산했던 것을 다시 살펴보자)

      이번엔 요녀석을 살펴보자. 여기서 은 단순히 새로 추가된 8비트와 기존 u(x)의 하위16비트(CRC-16이니까)에서의 low-order 8bit인 와의 합(XOR)이다. 결론은 꼭 1비트씩 할 필요없이 8비트씩 계산해도 괜찮다~라는것!!

      여기서는 8비트씩 계산을 해도 된다~ 라는 결론만 가지고 다음 챕터로 넘어가보자.

       

      4. Table Lookup Algorithm

      위에서 이 값은 8비트이므로 총 256개의 값을 가질 수 있고, 따라서 이 값은 미리계산 되어질 수 있다. (영어로 하자면 precomputable하다…정도? 모든 경우의 수를 다 계산해 놓는것) g(x)가 CRC-16의 경우 값은 최대 16비트값을 가지게 되므로 해당 테이블의 크기는 2byte * 256 = 512byte가 되겠다. CRC-8이라면 256byte를 가질 것이다. 계산 순서는 다음과 같다.

      1. CRC register를 0x0000 으로 만든다. (값이다)
      2. 를 구한다. (계산)
      3. CRC register를 8비트 right-shift한다.
      4. 미리 계산해둔 CRC Lookup table에서 해당값을 CRC register에 XOR 연산을 한다.
      5. CRC 계산할 byte-stream data가 끝날때까지 2~4 단계를 반복한다.

      끝나고 나면 CRC register에 전체 byte-stream data에 대한 CRC 값이 있게된다. 끝!!

       

      5. Reference

      A Tutorial on CRC Computations

      Ramabadran, T.V.   Gaitonde, S.S.  
      lowa State Univ., Ames, IA

      WCDMA Downlink Symbol Level Processing에 대해서 써보고자 한다. 주로 3GPP 25.212 spec에 따라서 쓸 꺼당…

      데이터의 흐름은

      1. CRC Attachment
      2. TrBK concatenation / Code block segmentation
      3. Channel coding
      4. Rate matching
      5. 1st insertion of DTX indication
      6. 1st interleaving
      7. Radio frame segmentation

      상위 1-7 순서를 단위로 해서 묶어서

      1. TrCH Multiplexing
      2. 2nd insertion of DTX indication
      3. Physical channel segmentation
      4. 2nd interleaving
      5. Physical channel mapping

      의 순서대로 처리하게 된다.

       

      각각의 단계에 대해 Study를 한 후 해당 내용을 정리할 생각이다. 이는 뭐 그냥 3GPP spec내용이니까 대외비인 것도 없고, 사내 blog에는 그냥 doc파일로 저장해서 올려야지… blog api가 없어서 귀찮단 말이지 ^^;;;

      CRC attchment는 공부 좀 했었는데…시간 좀 지났다고 다 까먹었다 -.-;;;

      물론...뭐 codec 같은 특수 계산만 죽어라 하는 경우에야...해당 플랫폼에 최적화를 해야되기 때문에, 어쩔수 없는 경우긴 하지만...

      여튼 종속적인 개발은 별루다!

      흠흠;;; 자료구조의 기본기만 잘 다뤄도...일단 80%는 먹고 들어간다. 나머지 20%를 최적화 하는건 해당 플랫폼전용 기술. (20%라고는 해놨지만 저부분에서 성능향상이 200% 정도 될수도 있긴하다 ^^;;) Performance Critical한 작업이라면 80%은 기본이요, 20%도 기본으로 해야겠지만...글쎄? 저 20%라는 영역을 위해선 해당 플랫폼에 대한 깊은 이해가 필요하다. 대충해봐야 오히려 컴파일러만 못할 수 있다는 것. 그럼 들인 노력만큼 뽑아낼 수 있느냐가 문젠데... 약간 회의적이다. ㅎㅎㅎ 그냥 inline asm 정도 쓰는것만 따진다면 20%중에서 아주 극소수랄까?

      예를 들어 직면한 문제로써, CEVA dsp 에서 개발을 진행해야된다. 근데...이넘은 VLIW인거다 -_-;; 정말 best effort를 내려면, core 내에 어떤 유닛이 최대한 동시에 진행될 수 있는지 꿰고 있어야되고, 그에 맞춰서 구현이 가능한 수준에 이르러야한다. 뭐...상사들은 그걸 다 알아야된다고 말은 하지만 글쎄??

      간략히 저 위에 올라갈 어플을 설명하자면, WCDMA 기지국 SW다. R99 + HSDPA + HSUPA 요렇게 크게 3가지로 나뉜다. R99는 솔직히 데이터량이 크지도 않다. 그리고 HSDPA,UPA는 대부분의 계산이 ASIC쪽에서 이루어진다. 즉, 최적화를 행할만한 부분이 R99라는 소린데...계산량이 밀려오지도 않을껀데 그걸 최적화 해봐야. -_-a;;

      뭐...해당 플랫폼에 대한 이해가 필요없다는건 아니고...일단 기본기부터 제대로 짜는게 더 중요하단 소리. 여기서 기본기란? 일단 Computer자체에 대한 이해(register + L1 + L2 뭐 이런 구조라던가...메모리 관련한 내용들이 많겠지), OS에 대한 이해, 기본적인 자료구조 및 해당 알고리즘들. 그런거는 무시하고 해당 플랫폼에 대해서만 최적화하는건 본말전도라는것.

      아 오랜만에 블로그 포스팅 막하고 있네 ^^;; (무플의 안습은 계속된다 쭈욱~~~ -ㅁ-;;)

      CPU와 DSP간의 Interface를 위한 문서가 있다. 근데 이게...워낙 변수들도 다양하고 해서, DSL(Domain Specific Language)를 이용하면 간단한 룰의 Text 로 부터 Interface Word document뿐만아니라, C에서 사용되는 header 파일도 뽑을수 있단말이지. 즉 One source, Multi use가 된다.

      간단한 Tech Demo를 보여줬으나...뭐 좀 신기해 하고(워드를 직접 치는게 아니라 자동생성이 가능하다는 거에 신기해 했을듯...)...다만 거기까지. 제대로 된 걸 만드려면 최소 한달 길게는 두달 정도는 잡아야되지않겠느냐는 말에 그럴꺼면 딴거 스터디하는게 더 낫다. 는 결론 ㅎㅎㅎ

      뭐 틀린말은 아닐수도 있다. 회사라는게 시간과의 싸움이 있는것도 있으니까...그래도 뭐랄까. 너무 근시안적인것만 보는건 아닐까. 이번에 해놓고나면 다른 프로젝트에도 얼마든지 적용이 가능할 것이고, 업그레이드된 무언가가 나올 수도 있다. (활용 가능한 분야를 두어개 더 설명도 충분히 했었다 -_-;; 그 이상도 나올수 있다는것)

      다른 팀원들이...뭔가 좀 느꼈으려나? 귀찮은 일을 자동화 한다는 개념에...뭔가를 느꼈으면 참 좋으련만 -_-;;;;
      저번주에 있었던 일인데...

      알고리즘 파트쪽에서 패킷 스케쥴링 구현을 했고 그걸 dsp에 포팅하는 작업을 같은 팀원이 하고있길래, 그냥 이것저것 얘기를 좀 해봤었다. (간섭? ㅋㅋㅋ 왜 근데...그런게 재밌다능...;; 내 일 아니니까 더욱 재밌는듯? 냐하하) 얘기하다보니...구현이 거참. 한숨만 푹푹. ㅎㅎㅎ

      Data 형식은 (id, value) 요렇게 pair형식. 요거를 100여개? 정도 value-order로 소팅을 해야되는데...알고리즘쪽에서 가져온 구현은? 짜잔~~~
      id 용 구조체 따로, value용 구조체 따로 구현한 후에, value 퀵소팅 실행. value swap 시마다 id쪽도 같이 swap.... 뭐 그렇게 해도 구현은 되지...되고말고;;;;

      그.러.나.
      id, value가 같이 있는 구조체 하나 선언한 뒤에, compare function 하나 만들고, Standard C Library에 있는 sort 함수 한번 호출해주면 만사 오케이 인거다...-_-;;;
      즉, 알고리즘쪽 분은...구조체의 경우 어떻게 sort를 해야되는지 몰랐던것.

      저분을 콕 집어서 비난하는것이 아니지만...자료구조쯤은 알아야하지않을까? 흠냐;;
      문제는 대다수가 스킬개발은 뒷전 ㅎㅎㅎ 에효~~~
      Visual Studio  같은 경우는...자체 에디터에서 (vi, emacs도 있지만 그 둘은 내가 안쓰니까...) indent를 정리해주는 기능이 있다.

      그런게...기존에 indent가 뒤죽박죽인 c파일을 정리하기 위해서 VS를 까는건...왠지 비합리적이잖아? 그래서 indent를 찾아보고 테스트해봤는데....(GNU indent).... 이거 뭐 쓰기도 불편하고 왜 제대로 안되는지 알수가 없었다 -_- 내가 원하는대로 잘 안움직인다고 해야되나...

      그래서 좀 더 뒤적거려보니 'AStyle' 이라는게 있었다. 오...매우 좋음. 옵션도 구질구질 많지도 않고, 적용도 깔끔하게 되고.

      링크는 http://astyle.sourceforge.net/ 이것.
      리눅스,윈도버젼 죄다 있으니 (MAC OS X 까지도) 좋고...
      subversion이랑 연동시키기에도 좋을 것 같다.

      POSIX 스레드 동기화쪽에 보면...Readers/Writer mutex 객체가 따로 존재한다. 그런데...이게 자체 제공되지않는 시스템도 존재한단 말이지. (현재 몸담고있는...DSP쪽이라던가.)

      그래서...혼자서 생각해봤는데, 와...이거 참 쉽지않다. writer끼리의 경쟁은 mutex로 정한다고 치더라도, readers와 writer의 경쟁은 어떻게 방지할 것인가?

      그래서 결국은 구글신께 문의.

      결과는 http://doc.trolltech.com/qq/qq11-mutex.html 여기.

      아주 심플하다. ^^ semaphore랑 mutex 2가지만 시스템에서 제공하면 얼마든지 구현이 가능!!

      현재 회사에서는 모바일 플랫폼 SW 개발쪽 인력을 엄청나게 확장하고 있는것 같다.
      아마..플랫폼을 개발한다고 하니...일단 OS는 리눅스를 사용하겠지? (설마 새로 만들진않을테니)

      그런데...들려오는 소문에 의하면(어디까지나 소문이다~ 카더라~~ ㅎㅎ) 상사분이 상당히 FM이시라고한다. 옷은 이렇게 입어야되고...기타 생활은 이렇게 해야되고. 기타등등...

      물론 그렇게 하면...획일적인 모습으로...좀 보기엔 그럴듯 하려나? 근데...SW를 개발하는 곳에서 너무 빡빡한것은...좀 더 안좋을것 같은데 말이다. 일단 개발자는 기계가 아니란말씀. 편안한 생활에서 집중에서 반짝! 하는게 정말 엄청난 효율을 가져다 주는것이다. 라는 믿음이 있긴한데...(일반적으로 그렇지?) 회사입장에서도 좋은 효율을 가져다 주는게 더 이익일거 같긴한데.

      과연 저 2가지의 상관관계는 어떨까? 일반적인 SW기업들 문화를 살펴보면...생활적 제제가 없는쪽이 더 좋은거 같긴하다 ㅎㅎㅎ (엉성한 결론으로 종결!!!)

      명시적이며 사용하기 편리한...아주 괜찮은 동기화 표현을 봤다.

      It`s so Cool~~~~!!

      내용은 여기 로...

      + Recent posts