※ 질문/내용오류/공유할 내용이 있다면 jinkilee73@gmail.com으로 메일 주세요 :-)


'시작하며'에서 말했듯이, 정말 어디서부터 시작해야할지 모르겠다. 그렇지만 한번 시작해보자. 네트워크란 무엇일까? 위키피디아에서는 다음과 같이 설명했다.


computer network is a telecommunications network that allows computers to exchange data. The physical connection between networked computing devices is established using eithercable media or wireless media.


즉, (컴퓨터) 네트워크란 컴퓨터가 정보를 교환하도록 하게하는 그런 네트워크를 말한다. 왜 사람들은 네트워크를 사용했을까? 옛날에는 컴퓨터라는 것이 이렇게 많지 않았다. 게다가 일반인들은 감히 사지 못 할 정도로 비싼 제품도 있었다고 한다. 이러한 제품을 어떻게 개개인이 다 가지고 있는가?! 나눠쓰는 것이다. 그것을 네트워크를 통해 가능케 한 것이다. 당시에는 여러 단말기를 통해 메인 프레임에 접근 가능하도록 네트워크를 설정하여 사용했다고 한다.


보통 네트워크를 설명할 때 빠지지 않고 나오는 이야기가 인터넷이고 인터넷을 설명할 때 빠지지 않고 나오는 이야기는 ARPANET이다. ARPANET은 미국 국방부의 연구 개발국의 네트워크로 당시에는 개발국 내에서만 사용하던 작은 네트워크일 뿐이었다. 그런데 이것이 여러 개의 작은 네트워크와 합쳐지다보니까 지금의 글로벌 인터넷이 되었다는 아주 유명한 이야기이다.



이와 같이 그냥 어떤 그룹이 여러 개 묶였다고 생각하면 된다. 묶이고 묶이다 보니 그 크기가 지구 전체를 아우르게 되어 인터넷이라는 큰 네트워크가 형성되었던 것이다.


사실 지금까지는 모두가 아는 이야기이다. 그러면 이제부터는 하나의 네트워크를 만들어가는 과정부터 이야기해볼까? 하나의 네트워크 이것은 지구 전체를 봤을 때는 굉장히 작은 지역적인 네트워크일 뿐이다. 따라서 Local Area Network(LAN) 라고 부른다.


이제부터 당분간 앞으로의 포스팅에서는 LAN 만을 이야기할 것이다. 당분간 TCP/IP를 통한 외부 네트워크를 접근하는 것은 잊도록 하자. TCP/IP를 논할 때가 되면 그 때 다시 이야기하려고 한다.


컴퓨터가 30대 있는 사무실에 LAN을 구성해볼까? 30개의 컴퓨터를 이어보자 :-)

뭐가 필요할까? 우선 30대의 컴퓨터가 필요할 것이다. 그리고 이 30대의 PC를 연결할 선(UTP Cable)이 있어야 하고 이 선을 꽂을 네트워크 스위치가 있어야 한다. 


여기서 스위치란 방에 있는 불 킬때 똑딱 거리는 그 스위치가 아니라 하나의 컴퓨터 정도로 생각하자. 뭔지는 잘 모르겠지만 스위치에 케이블을 꽂으면 PC들이 통신을 할 수 있는 그런 것이라고 생각하자. 스위치에 대한 자세한 이야기는 나중에 해보자.


아무튼 다시 네트워크를 구성하는 이야기로 들어가서, 이제 대충 생각하기를 컴퓨터를 선에 연결해서 스위치에 연결하면 대충 될 것 같다.



케이블을 PC에 꽂으려고 하는데 이런, LAN 카드가 없다;; 용산 가서 사오기로 하자. 음, 그런데 뭘 사와야 할까? 아무거나 사오면 안 된다. 


여기서 중요한 이야기를 해보자. 세상에는 여러 방식의 네트워크 방식이 있다. 네트워크가 작동하기 위해서는 네트워크가 동작하는 일련의 규칙이 있어야 한다. 가령, 1번 PC부터 30번 PC가 줄을 서서 통신할 기회를 기다린다든지, 가장 데이터가 많은 PC가 네트워크에서 데이터를 전송하도록 하자 라든지. 뭔가 같이 지키는 규칙이 필요하다.


이 세상에는 몇 가지의 네트워크 방식이 있을까? LAN 카드에 적용되는 방식들은 보통 다음과 같다.


1. Ethernet (전 세계 네트워크의 90%는 이 방식을 사용한다.)

2. Token Ring

3. FDDI

4. ATM


즉, 하나의 LAN을 구성하기 위해 LAN 카드를 구입할 때는 같은 방식의 LAN 카드를 사야 통신이 가능하다. Ethernet LAN 카드가 25개 밖에 없어서 나머지 5개는 Token Ring LAN 카드를 구입했다면 통신은 불가능하다. 30개 전부 Ethernet을 사든 Token Ring을 사든 해야한다. 


자 Ethernet LAN 카드 30개 구매하였고 PC에 설치도 완료했다. 이제는 진짜 스위치에 캐이블을 끼워서 PC를 연결해보자.


여기서 궁금증이 생긴다. 도대체 왜 다른 종류의 LAN 카드로는 통신이 불가능하다고 하는거지? 궁금증을 해결하려면 각각을 공부해보는 수 밖에 없다. 먼저 Ethernet을 알아보자.


Ethernet은 보통 CSMA/CD (Carrier Sense Multiple Access/Collision Detection)이라는 프로토콜을 사용한다. 네트워크에서 지켜야하는 규칙을 의미한다. Ethernet LAN 카드로 구성된 네트워크에서는 CSMA/CD라는 규칙을 지켜야 한다고 이해하면 된다. 그러면 CSMA/CD는 어떤 규칙일까? 쉽게 말해서 "알아서 눈치껏 통신하자"이다. 30개의 PC가 연결되어있는 네트워크에서 두 개 이상의 컴퓨터가 동시에 데이터를 보내면 충돌이 발생한다. 충돌을 피하기 위해 알아서 눈치껏 통신하자는 이상하고 아리송한 프로토콜이다. 


CSMA/CD는 다음과 같이 동작한다. Ethernet 네트워크 상의 한 대의 PC A가 네트워크 상황을 살펴본다. 아무도 없다. (A는 F와 통신하고 싶어한다고 하자.) 따라서 눈치껏 F한테 데이터를 보낸다. F는 데이터를 잘 받겠지? 그러면 이제 PC B를 보자. B가 네트워크 상의 C와 통신하려고 한다. 아무도 없길래 데이터를 보냈는데 마침 그 때 A가 데이터를 다른 PC에 보내서 충돌이 발생했다. 이러면 A와 B는 충돌을 감지하고 또 다시 알아서 눈치껏 데이터를 각자의 목적지에 보낸다. 만일 이 때도 실패하면 어떻게 되냐고? 계속 눈치껏 보낸다. 15번까지 연속으로 실패하면 그 때는 A와 B는 "이 네트워크에서는 통신 못 하는구나"하고 판단한다. 아래의 그림과 같다.



앞으로의 포스팅에서 조금 더 자세히 다룰꺼지만 지금은 그냥 대충 Ethernet이 CSMA/CD라는 프로토콜을 사용하고 그 뜻은 "눈치껏 알아서 통신하자" 까지만 알고 넘어가자. 


그 다음에는 Token Ring 이다. Token Ring 네트워크에서는 토큰을 가지고 있는 PC만 데이터를 전송할 수 있다. 그 토큰은 네트워크 상에서 계속 옆으로 전달된다. 아래와 같다.



이 네트워크에서는 토큰이 있는 PC만 데이터를 전송할 수 있기 때문에 데이터가 충돌날 일은 없다. (단, 토큰이 하나일 경우만!! 몇몇의 토큰링 네트워크에서는 토큰이 몇 개 있는 그런 토큰링 네트워크도 있다고 한다.)


CSMA/CD에 대해서는 다음 포스팅에서 이야기하기로 했지? 그러므로 이번 포스팅은 마치려고 한다. 사실 이번 포스팅의 내용은 누구나 네트워크를 공부한 적이 있다면 들어봤을 또는 익숙할 만한 이야기이다. 그렇지만 이 블로그 알지? 기초부터 이야기하는 그런 블로그라는 것. 


마지막으로 위에서 계속 뜬 구름처럼 이야기되었던 스위치가 어떻게 생겼는지 보여주고 이 포스팅을 마치려고 한다.




p.s. 저 구멍에 네트워크 캐이블을 연결하면 된다고 한다.

'Computer Networks' 카테고리의 다른 글

[NW] Address Resolution Protocol (ARP)  (2) 2013.06.13
[NW] Media Access Control (MAC)  (0) 2013.06.13
[NW] Hub, Bridge and Switch  (2) 2013.06.11
[NW] CSMA/CD  (0) 2013.06.07
[NW] The definition of a network  (2) 2013.06.05
시작하며...  (0) 2013.06.04
Posted by 빛나유

댓글을 달아 주세요

  1. 화신선 2014.03.21 08:48  댓글주소  수정/삭제  댓글쓰기

    제가 어렴풋한 기억으론 세그먼트 단위로 구분을 우선 구분을 하고 같은 세그먼트간에
    통신을 할 시 충돌이 일어나는 걸로 알고 있습니다.(아닐수도..?)
    첫번째 그림에서 A가 F로 데이터를 보내고, B에서 C로 데이터를 보내기를 시도하다
    서로 충돌을 설명하는 그림인데, 전혀 모르는 사람 입장에서는 서로 다른 곳으로
    보내는데 왜 충돌이 일어나지? 라는 의문이 들것 같기도 한데요~
    충돌을 하게 되는 환경을 우선 설명해 주시면 이해가 잘갈 것 같아요 ^^
    그림으로 15번 연속으로 보내다 실패하면 더이상 통신을 시도하지 않는다는 그림을 설명하기
    위한 그림으로 보이긴 한데, 그림먼저 보게 되면 스위치가 충돌감지 제어를 못하는게
    아닐까 하는 오해를 할까 싶어서요~ ㅋ

    • 빛나유 2014.03.22 01:49 신고  댓글주소  수정/삭제

      '서로 다른 곳으로 보내는데 왜 충돌이 일어나지?' 충분히 들수 있는 생각이네요...
      역시 혼자 쓰고 보면 이런게 안 보입니다ㅠㅠㅠ
      충고 감사합니다!! 지금은 수정 못하지만(집이 아니네요..ㅠㅠ) 조만간 수정하께요ㅋㅋ

      악.. 그런데 어떻게 그려야 오해의 소지가 없을까요...ㅋ

앞으로 조금 포스팅이 뜸해질지도 모른다. 나에게 있어서 굉장히 슬픈 일이 아닐 수 없다. 보통 업무 끝나고 쉬는 시간에 항상 포스팅할 것들 정리하고 생각하면서 시간을 보내는데 이제는 그러지 못 할지도 모른다. 왜냐하고? 네트워크를 공부하게 되었으니까. 나는 포스팅하는데 있어서는 완벽하게 하고 싶다. 정말 제대로 포스팅하고 싶다. 성의있게 자세하게 정확하게 그리고 쉽게 포스팅하고 싶다. 그런데 네트워크는 아직 나에게 있어서 개념이 뭉뜽그렇다. 나도 잘 모르는 상황에서 어떻게 포스팅을 하느냔 말이다. 슬프다. 정말...


그렇지만 이 사람이 포스팅을 관뒀구먼? 이라고 생각은 안 해줬으면 좋겠다. 나는 항상 포스팅을 생각한다. 포스팅이 조금 안 올라오면, 이 사람이 공부하느라 헤메고 있구나~ 하고 이해하면 될 것 같다.


어떻게 시작하지? 난 처음부터 기초적인 것부터 차례차례 설명해나가고 싶은데 네트워크도 그게 가능할까? 이 블로그의 수준은 대학교에서 컴퓨터를 배우고 있는 사람이라면 누구라도 이해할 수 있을 정도의 수준인데(아직은) 처음부터 TCP/IP를 OSI 7 Layer에 빚대어 표현하여 설명하면 무지하게 어려울 것이다. 물론, 네트워크를 공부한적이 없는 사람들의 입장에서는 말이다.


그래도 나는 설명 하나는 잘 한다고 생각한다. 하나 하나씩 풀어갈 네트워크의 비밀. 지금부터 시작됩니다.

'Computer Networks' 카테고리의 다른 글

[NW] Address Resolution Protocol (ARP)  (2) 2013.06.13
[NW] Media Access Control (MAC)  (0) 2013.06.13
[NW] Hub, Bridge and Switch  (2) 2013.06.11
[NW] CSMA/CD  (0) 2013.06.07
[NW] The definition of a network  (2) 2013.06.05
시작하며...  (0) 2013.06.04
Posted by 빛나유

댓글을 달아 주세요

※ 질문/내용오류/공유할 내용이 있다면 jinkilee73@gmail.com으로 메일 주세요 :-)


이번 블로깅에서는 하드웨어에 dependent 한 최적화를 해보자. 하드웨어 dependent한 최적화란 무엇인가? 즉, 특정 하드웨어에서 적용가능한 최적화 기법이라는 뜻이다. 에이~ 그럼 의미가 없잖아? 라고 생각하는 사람이 있을 것이다. 아니라고 말도 못 하지만 꼭 그렇다고 말도 못 한다. 왜냐하면 요즘 하드웨어 구조가 뭐 거기서 거기라.. 왠만하면 앞으로 소개할 방법으로 개선이 된다고 한다. 자 어떤 방법이 있는지 알아보자.

우선, 예제는 이전 블로그에서 사용했던 예제를 가지고 사용해보자. 이전의 hardware independent 한 최적화에서 가장 효율이 좋았던 코드는 아래와 같다.


이 코드를 또 어떻게 최적화할까? 루프 한번 돌 때 두번의 연산을 해볼까? 그러면 for문에서 하는 i < length 비교하는 것과 i++하는 회수가 반이 줄겠지?



그래서 이렇게 한번 바꿔봤다. 같은 코드지만 for 문 안에서 i+=2로 바꿨다. 그리고 switch문을 통해서 나머지 부분을 수행해주었다. (C code 자체에 대한 이해는 독자들에게 맞기겠다.) 이렇게 해서 돌려보면 평균적으로 35000us 의 속도를 내던 프로그램이 25000us로 줄어든다. 결국 for 문을 돌때 계산되는 overhead 등을 반으로 줄인 효과이다. 그렇다면 i+=3, i+=4, i+=5 등을해서 더욱이 개선을 할 수 있지 않을까? 한번 해보자.



loop를 10000000번 돌기 때문에 loop 한번당 3개의 연산을 하면 마지막에 하나가 남는다. 따라서 switch 문에 case1만 해줬다. 원래 제대로 된 프로그램이라면 case 0과 case 2가 있어야겠지만 생략하겠다. 이렇게 했을 경우 21000us로 또 속도 개선이 나타난다. 그리고 아래의 표를 보자.


 

 i+=3

 i+=4

 i+=5

 속도

 21000us

18000us 

 17000us


개선이 나타난다. :-) 특히나 i+=5같은 경우 거의 i++와는 두배의 효율을 보인다. 이러한 방법으로 개선해나가는 방법을 loop unrolling이라고 한다.


그런데 loop unrolling이 항상 효과를 보이는 것은 아니다. float 연산에 대해서 * 연산을 할 때는 효과가 거의 없다. 그 이유를 알기 위해서 우리는 지금껏 열씸히 배운 어셈블리 언어를 이용할 것이다. 아래의 어셈블리 코드는 위에 있는 2-way(i+=2) loop unrolling C코드의 for문에 해당한다.



(아래의 분석한 부분은 순수히 저의 허접한 실력으로 분석한 내용이니 조금은 의심을 가지고 봐도 됩니다.)

점프하는 부분 전부 빼고 순수히 for 문 안에서의 연산을 하는 부분만 고려하여 119번째 줄부터 126번째 줄까지 봐보자. 어셈블리 언어로 보면 복잡하니까 아래와 같이 그림으로 봐보자.



각각의 레지스터 값에 대한 각각의 명령어의 효과를 나타낸 것이다. 예를 들어 flds    (%eax) 명령어는 %eax로부터 값을 로드한 후 그 값을 mov 명령어를 통해서 복사하는 것이다. 따라서 load 명령어가 %eax를 operand로 갖고 그 결과가 mov 연산자로 들어가며 그 결과는 st0~7 레지스터 스택에 쌓이는 것이다.


여기서 잠깐, 위 코드에서 우리가 안 배운 레지스터와 명령어가 있다. st0, st1, ... , st7 이런 레지스터 배운 적 없다. flds? fmuls? fmulp? 배운적 없다. 이 부분에 대해서는 나중에 설명하도록 하자. 지금 다루는 내용을 이해하기 위해 필수적으로 알아야 할 내용은 아니라고 본다. 그래도 궁금한 사람은 아래의 링크를 따라가서 찾아보면 된다.


st0~7 : http://cs.smith.edu/~thiebaut/ArtOfAssembly/CH14/CH14-3.html

flds, fmuls, fmulp : http://cs.smith.edu/~thiebaut/ArtOfAssembly/CH14/CH14-4.html#HEADING4-104


위의 그림은 명령어를 그대로 해석해놓은 것이기 때문에 따로 설명은 하지 않겠다. 아무튼 저 그림에서 오른쪽의 명령어를 보기 좋게 왼쪽으로 끌면 아래와 같은 그림이 나온다.



이제 본격적으로 왜 성능 개선이 없는지 이야기를 해보자. 위의 그림은 아까 말했다시피 for 문 안의 연산 부분이다. 즉 위에서 밑으로 연산들을 타고 내려가면서 data[i]에서 data[i+1]을 거쳐서 가장 밑에 있는 data[i+2]로 가는 것이다. 여기에서 st0~7 레지스터를 보자. data[i] ~ data[i+2]까지 갈 때 mul 연산이 두 개이다. 첫번째 mul 연산의 결과가 끝나야 그 값으로 두번째 mul 명령어를 수행할 수가 있다. 즉, 병렬 연산이 불가능하다는 것이다. (컴퓨터 구조에서 파이프라인 구조를 공부하면 이 부분을 자세하게 다룰 수 있다.)


그러면 어떻게 하면 병렬로 연산이 가능하게 만들 수 있을까? 사실 이 부분을 실패했다.-_- 포스팅이 여기서 끊키고 몇 일동안 정체되어있었던 이유가 바로 그것이었다. 내가 뭘 알아야 포스팅을 하지?! 자, 다시 본론으로 들어와서. 프로그래밍의 효율이 다른 방법으로 좋아지기는 했다. 아래의 코드를 보자.



사실 효율이 그렇게 좋아지지는 않고 조금 좋아졌다. 그 이유를 생각해보자. for 문 안을 보면 acc 하나가 아니라 acc1과 acc2 두개를 사용하여 따로 계산을 하고 있다. 그리고 마지막에 *dest = acc1 OP acc2 로 마무리를 해주는 방식이다. 이렇게 하면 다음의 어셈코드가 나오게 된다.



가장 눈에 띄는 변화는 곱하기하는 함수의 변화와 flds 함수를 fmulp를 하기 전에 두 번 수행한다는 것이다. (사실 그 두 개 빼고는 변한게 없다.) 역시 어셈블리 코드는 한 눈에 보기는 어렵다. 그림으로 바꾸면 아래와 같이 바꿀 수가 있다.



추측하건데, 프로그램의 성능이 개선된 이유는 곱하기 함수의 종류 때문이라고 생각한다. 이전의 버전에서는 어셈블리코드에서 곱하기 함수가 fmuls와 fmulp였다.

fmuls        -16(%ebp)

fmulp        %st, %st(1)


반면, 이번의 코드에서는fmulp가 두 개이다.

fmulp        %st, %st(1)

fmulp        %st, %st(1)


무슨 차이일까? 바로 메모리 접근 회수의 차이라고 본다. 이전 버전에서 fmuls를 할 때는 -16(%ebp)라는 메모리 접근을 하는 반면, 현재의 combine1함수에서는 레지스터에 있는 값을 직접 사용하여 곱하기를 하는 것이기 때문에 곱셈 속도가 미약하지만 개선되는 것이 아닌가 싶다.


그런데 사실 내가 바랬던 개선 원인은 이것이 아니다. 내가 원했던 개선 원인은 새로운 레지스터, 예를 들어 %ebx,를 사용하여 첫 번째 곱셈이 끝나기 전에 두 번째 곱셈을 실행할 수 있도록 하는 것이다. 즉 병렬 처리를 통한 개선이었다. 그런데 floating point 연산을 리눅스에서는 꼭 st0~7 레지스터를 사용하여 연산을 해버리니 병렬 처리가 불가능했던 것이다.


아무튼 중요한 점은 변수 하나를 더 써서 레지스터를 더 많이 활용할 수 있는 효과를 낼 수 있다면 프로그램 개선을 기대할 수 있다는 사실이다.


p.s. 이래저래 포스팅을 마무리 할 수는 있게 되었다. 뭐랄까? 이 찝찝하면서도 시원한 기분은...


Posted by 빛나유

댓글을 달아 주세요