'HotStudy+-+/...*ETC*...'에 해당되는 글 25건

  1. 2009/06/25 [Review] Software-controlled Priority Characterization of POWER5 Processor (2)
  2. 2009/06/25 For Semantic Web Final Exam
  3. 2009/06/19 [Advanced Computer Architecture] Advanced Memory Hierarchy
  4. 2009/06/19 [Advanced Computer Architecture] Directory based multiprocessor
  5. 2009/06/19 [Advanced Computer Architecture] Symmetric Multiprocessor
  6. 2009/06/19 [Advanced Computer Architecture] Vector Computers
  7. 2009/06/02 [Advanced Software Engineering] Double Auction Model
  8. 2009/06/01 [Advanced Computer Architecture] Simultaneous Multithreading (2)
  9. 2009/06/01 [Advanced Computer Architecture] Instruction level parallelism - Tomasulo Algorithm
  10. 2009/06/01 [Advanced Computer Architecture] Instruction level parallelism
  11. 2009/06/01 [Advanced Computer Architecture] Memory Hierarchy Review
  12. 2009/06/01 [Advanced Computer Architecture] Pipelining
  13. 2009/06/01 [Advanced Computer Architecture] Introduction
  14. 2009/06/01 [Advanced Software Engineering] MinneTAC (“One of TAC SCM Agents”) Model
  15. 2009/04/27 [Semantic Web] Survey of Ontology Engineering Methodologies
  16. 2009/04/22 [Advanced Software Engineering] Single Auction Model
  17. 2009/04/07 [Advanced Software Engineering] Minimum Load First Scheduling Model
  18. 2009/04/01 [Advanced Software Engineering] Round Robin Scheduling Model
  19. 2009/03/31 [Advanced Software Engineering] Processor + EF (Transducer + Generator) Model
  20. 2009/03/31 [Advanced Software Engineering] Generator + Processor + Transducer Model
  21. 2009/03/30 [Advanced Software Engineering] Generator + Proccessor Model
  22. 2009/03/30 SyntaxHighlighter
  23. 2008/12/22 [Review] AI Seminar
  24. 2008/04/11 뚭앙이의 설치형 블로그 도전기! -1-
  25. 2008/02/16 [Survey] Survey of NeOn Project

티스토리 잠정 폐쇄

티스토리 블로그는 문을 닫습니다. 지금까지 티스토리에 너무 많은 포스트가 있어서 네이버와 함께 올리고 있었지만 관리하기가 어렵네요. 네이버에서 타 블로그의 백업이 지원되지않아서 옮길 방법이 없어 그냥 두고 있었는데 차차 옮겨..

Jeremy
Jeremy 2012/05/03

퇴근길에 병원에 들러 뚜둥이 약 받아가지도 돌아왔는데... 오늘 두 개만 와 있을 줄 알았던 택배가 네 개...헐 뭘 그렇게 많이 질러댄거니...ㅜ_ㅜ 주말에 구입했는데 상품이 없어서 배송해주기로 한 작은 핸드백 근 10년간..

그들의 즐거운 한 때.

정말 오랜만이네요. 인형 포스팅을 하는게...ㅜ_ㅜ 뚜둥이 때문에 마음도 심난하고 우울하고 정신놓고 뚜둥이만 쳐다보고 있다가 뭔가 해야지 하고 셋팅을 했지요. 오랜만의 연휴였는데 아무것도 남기지 않으면 더 우울할 것 같아서요...

ㅋ컴구 레포트 ㅜ_ㅜ

이제 이것만 하면 끝이다..쿄쿄쿄

열심히 했으니 에이 뿔 주세요..ㅠ_ㅠ


Botine, C., F. Cazorla, R. Gioiosa, A. Buyuktosunoglu, C.Y. Cher and M. Valero

Proceedings of the 35th International Symposium on Computer Architecture, pp. 415-426, 2008

 

1.     Introduction

ILP 의 한계는 프로세서의 성능을 향상시키는 전략으로서 TLP의 활용을 촉진시키고 있다. Common TLP 패러다임은 Simultaneous Multi-Threading Chip-Multi-Processor, 혹은 이 둘의 혼합이다. IBM POWER5dual core processor로 각 코어가 두 개의 Thread를 실행한다. ThreadGCT(reorder buffer), BHT, TLB등의 리소스를 공유하는데, IBM POWER5 시스템은 HW mechanism을 사용하여 Thread 간 리소스를 적절히 분배하고, 여기에 SW/HW co-design을 통해서 8개의 priority level을 갖는 instruction decode rate을 제어 mechanism을 사용한다. SW-controlled priority application type에 따라서 throughput execution time 모두를 크게 향상시킬 수 있다. 이 논문의 주요 contribution:

특정한 workload characteristic을 갖는 선택된 micro-benchmark 집합을 가지고 실험하여, 어플리케이션의 실행시간에 대한 POWER5 priority mechanism의 효과를 자세히 분석하였다.

서로 다른 metric, aggregated IPCexecution time을 향상시키기 위해 POWER5 priority가 어떻게 사용되는지를 보이는 어플리케이션 case study를 제공한다.




2.  The POWER5 Processor


2.1 Dynamic HW resource balancing

POWER5HW dynamic resource balancing을 제공하는데, ThreadL2 cache threshold에 도달하거나, TLB miss이거나, 너무 많은 reorder buffer entry를 사용했을 때, unbalanced한 리소스의 사용이 있다고 판단하여 blocking한다

- Stall: congestion이 해결될 때까지 offending thread instruction decode를 멈춘다.

- Flush: congestion이 해결될 때까지, dispatch를 기다리고 있는 offending thread의 모든 instruction flush하고, Thread가 더 이상 추가적인 instructiondecode하지 않도록 한다.


2.2 SW-controlled priorities

SW-controlled prioritydecode stage에서 HW에 의해 수행되는데, 일반적으로, 높은 우선 순위는 더 높은 수의 decode cycleThread에 할당한다. primary thread(PThread) secondary thread(SThread)가 있다고 하고, 각각 PrioP, PrioS의 우선 순위를 가지고 POWER5의 두 코어 중 하나에서 동작한다고 하자.


 …..(1)



RPThreadSThread의 우선 순위의 차이인, PrioP - PrioS를 사용해서 계산된다. 더 높은 우선 순위를 갖는 ThreadR-1 decode slot을 받고, 낮은 우선 순위를 갖는 Thread는 나머지 slot을 받는다. PThread로 실행되는 프로세서는 SThread로 실행되는 프로세서에게 손해를 주어서 성능이 증가한다. Thread가 같은 우선 순위를 갖는 특별한 경우, slot을 교대로 받는다.



1. Software-controlled thread priorities in the IBM POWER5 processor.


POWER5 에서 SW-controlled priority 0부터 7사이의 값을 갖는데, 그 의미와 변경 권한은 표1과 같다.

우선 순위는 OR instruction으로 변경되는데, OR X,X,X의 형태이며, X는 레지스터의 번호이다. Thread가 모두 우선순위 1을 가질 때는 둘의 차를 0으로 간주하는 것이 아니라, 우선 순위를 가지지 않은 것으로 하여 수행한다.



3.  Evaluation Methodology


POWER5 프로세서에서 SW-controlled priority mechanism의 능력을 알아보기 위해, 프로세서의 특정 성격 한 가지에 초점을 둔 micro-benchmark를 사용한다.


3.1 Running the experiments

이 논문에서는 FAME(FAirly MEasuring Multithreading Architectures) methodology를 사용한다. workload steady state로 될 때 그 프로그램의 IPC와 비슷하다면, average accumulated IPC가 대표 값이 될 수 있다. FAME average IPC steady state IPC의 차이가 threshold이하가 되려면 benchmark가 몇 번 실행되어야 하는지를 결정한다. threshold MAIV(Maximum Allowable IPC Variation)이라고 부른다. 이 논문에서는 1% MAIV에 도달하기 위해 각 micro-benchmark가 최소 10회 반복되어야 한다.


3.2 Micro-benchmark

      Micro-benchmarkInteger, Floating point, Memory Branch, 네 그룹으로 나뉘어 진다. integer group latency가 짧은 cpu_int latency가 긴 lng_chain_cpuint를 갖는다. memory group에서는 ldint_l2는 모든 load가 항상 L2 데이터 캐시에 hitting되고, ldint_mem은 메모리에 hitting된다. ldint_l2ldint_mem보다 높은 IPC를 갖는다. Branch 그룹에서는 br_hitbr_miss가 높고 낮은 hit prediction rate을 갖는다. 2는 벤치마크의 loop body structure를 보여준다. 몇 가지 벤치마크는 똑같이 행동하기 때문에 결과 분석에 영향을 주지 않는 것으로 판단되어, cpu_int, lng_chain_cpuint, ldint_l1, ldint_l2, ldint_mem, cpu_fp만을 다룬다.

2 Loop body of the different micro-benchmarks


3.3 The Linux kernel

IBM POWER5에서 동작하는 현재의 Linux kernel(2.6.23)은 아주 적은 경우에 SW-controlled prioritization을 사용하지만, 본 논문에서는 커널 모드에서 사용 가능한 모든 우선 순위를 유저가 set할 수 있는 인터페이스를 제공하는 non-intrusive kernel patch를 만들었다.<!--[if !supportLists]-->ž

  •  1부터 6까지의 우선 순위를 유저가 사용할 수 있게 하였다. 0 7은 유저가 hypervisor call을 하여 사용할 수 있다.

  • Linux kernel내의 SW-controlled prioritization을 사용하지 않고, 예측할 수 없는 우선 순위의 변화의 영향만을 실험하였다.

  • 유저 어플리케이션이 자신의 우선 순위를 변경할 수 있도록 /sys pseudo file system으로 인터페이스를 제공하였다.




4.  Analysis of the Results


POWER5 prioritization의 확장이 주어진 Thread의 실행에 어떤 영향을 미치는가와 prioritization throughput간의 trade-off에 대해 분석한다. 3은 두 개의 PThreadSThread의 우선 순위가 (4,4) SMT mode일 때와 single thread mode일 때의 IPC 값을 보여준다.


3 IPC of micro-benchmarks in ST mode and in SMT with priorities (4,4). pt stands for PThread and tt for total IPC.



4.1 Effect of Positive Priorities

그림 2positive priority(PrioP > PrioS)일 때, SThread의 우선순위 변화에 따른 PThread의 성능 향상을 나타낸다.

그림 2 Performance improvement of the PThread as its priority increases with respect to the SThread.


일반적으로, 낮은 IPC를 갖고 memory-bound가 아닌, lng_chain_cpuintcpu_fp와 같은 thread는 높은 우선 순위로부터 얻는 이득이 적다. ldint_l2ldint_mem과 같은 memory-bound benchmark는 다른 memory-bound thread와 함께 작동할 때 prioritization mechanism의 이익을 얻어, ldint_l2의 성능은 240%, ldint_mem의 성능은 70%까지 향상되었다. 반면, cpu_intldint_l1과 같은 높은 IPCthread는 추가적인 하드웨어 리소스로부터 이익을 얻을 수 있는 것과 같이 prioritization에 매우 민감했다. 그러므로, prioritization은 보통 total throughput이나 성능을 향상시킨다.

이 결과는 memory-bound benchmark가 유사한 요구조건의 다른 벤치마크와 경쟁할 때, POWER5 prioritization mechanism에 의한 영향을 받는다는 것을 보여준다. 그들은 순수한 cpu-bound benchmark보다는 덜 민감하며, memory-bound benchmarkco-schedule 되었을 때만 증가된 우선 순위에 대한 이득을 얻는다. 때문에 memory-bound benchmark는 다른 memory-bound benchmark와 스케줄 될 때가 아니면 prioritization되지 않아야 한다.

추가적으로, +2의 우선순위의 차이는 상대적인 포화점을 나타내며, 거의 모든 벤치마크가 자신의 성능의 95%이상에 다다랐다는 것을 의미한다. memory-bound benchmark는 가장 큰 성능의 증가가 +2에서 +3에서 나타나므로 이 규칙의 예외이다.


4.2 Effect of Negative Priorities

그림 3ldint_mem을 제외한 모든 마이크로 벤치마크의 성능이 negative priority(PrioP < PrioS)에 의해 큰 영향을 받는 것을 보여준다.

그림 3 Performance degradation of the PThread as its priority decreases with respect to the SThread.


이는 positive priority의 영향보다 훨씬 크다. 그림3 (f)ldint_mem이 다른 ldint_mem thread와 함께 수행되지 않는 경우에는 낮은 우선 순위에 민감하지 않은 것을 보인다. 일반적으로 높은 latency의 메모리 오퍼레이션이나 long dependency chain, 느리고 복잡한 오퍼레이션을 가진 thread는 우선 순위의 감소에 덜 영향을 받는다.

memory-bound benchmark는 다른 thread에 가장 큰 영향을 받는 것 중 하나이다. 우선순위 차가 -2에서 -3으로, -4에서 -5로 변할 때 성능이 명확하게 변화한다.

-5 와 같은 우선순위 차는 Pthread가 오직 memory thread가 남긴 것 만을 얻을 수 있기 때문에, transparent background thread와 같이 성능이 중요하지 않은 경우에만 사용되어야 한다.

+2 의 우선순위 차가 보통 최대 성능에 가깝다고 하면, -3은 성능 손실의 명백한 delta이다. Memory-bound thread의 경우 0부터 -2까지는 큰 성능의 변화가 없다. +2일 때를 고려해보면 대부분의 높은 IPC thread는 그 최대 성능의 95%에 달했고 즉, 우선순위 차가 +2/-2보다 커지는 것을 피해야 한다는 결론을 얻을 수 있다.


4.3 Optimizing IPC Throughput

POWER5 는 낮은 IPC task decode stalling하거나 시스템의 전반적인 성능을 저하시킬 수 있는 thread dispatch하는 등, global throughput을 향상시키는 몇 가지 HW mechanism을 사용하며, 대체로 효과적이다.

그림 4 Throughput w.r.t. execution (4,4). The legend shows the single-thread IPC of benchmarks.

그림 4는 총 throughput이 두 배 이상 증가할 수 있는 몇 가지 경우를 보여준다. 이는 우선 순위가 낮은 Threadslowdown의 비용에서 얻는 것으로 특히 lng_chain_cpuint와 같이 낮은 우선 순위의 Thread가 낮은 IPC를 가진 경우이다. 이러한 경우는 낮은 IPCThread가 이 slowdown을 커버할 수 있고, throughput이 중점적인 목표일 때 사용될 수 있다.

Cpu-bound benchmark의 성능이 그 우선 순위와 함께 향상되는데 반해 memory-bound benchmark는 상대적으로 일정하게 유지된다. 일반적으로 높은 IPCThread의 우선 순위를 증가시켰을 때 IPC throughput의 향상을 얻을 수 있다. 그림 5는 실제 시스템에서 SW-controlled prioritization total IPC 향상에 미치는 영향을 그래프로 나타낸 것이다.

그림 5 Total IPCs with increasing priorities


4.4 Optimizing execution time

높은 throughput이 항상 직접적으로 전체 어플리케이션의 짧은 실행시간으로 대응되는 것은 아니다. 병렬 시스템에서의 load balancing은 동기화된 태스크들이 같은 시간에 완전하게 종료되는 경우가 거의 없기 때문에 어려운 문제이다. 4 prioritization mechanism을 사용해서 전체 성능을 향상시키는 예시이다.

4 Execution time, in seconds, of FFT and LU.

 

4.5 Transparent execution

transparent thread foreground thread full speed로 수행되지 않아도 될 때 background thread가 리소스를 사용할 수 있도록 하는 mechanism이다. POWER5에서는 background thread의 우선순위를 1로 하여 이를 구현하였다. 그림 6 (a), (b) foreground thread가 각각 우선 순위 6 5 수행될 때 foreground thread에 대한 background thread의 효과에 대한 그래프이다. 대부분의 영향을 받는 threadldint_l1, cpu_int, ldint_l2memory-bound thread와 실행되었을 때이다.


그림 6 Primary thread Execution Time with respect to Single-Thread when SThread has priority 1



그림 6 (c) background thread의 우선순위가 6에서 2로 줄어들면서 foreground thread(ldint_l2, cpu_fp, lng_chain_cpuint)에 미치는 최대 효과를 보여준다. ldint_mem background로 하여 실행된 foreground thread가 가장 좋지 않은 성능을 보였음을 알 수 있다.

우선 순위가 6에서 2로 갈수록, cpu_fplng_chain_cpuint ST 성능의 10% 정도까지 background thread의 효과가 선형적으로 증가한다. ldint_mem은 우선순위 3 2일 때 갑작스럽게 증가한다. ldint_mem_2의 레이블은 ldint_mem foreground로 실행되면서, ldint_mem background는 아닐 경우의 성능을 나타낸다. 그래프는 다른 마이크로 벤치마크가 ldint_mem에 미친 효과가 대략 7%인 것을 보여준다. , 자신의 다른 복사본과 함께 수행되지 않는다면, ldint_mem은 항상 큰 성능의 저하 없이 foreground로 수행된다는 결론을 얻을 수 있다.

마지막으로 그림 6 (d) background thread의 성능을 보인다. 각 포인트는 모든 background thread의 평균을 나타내는데 ldint_mem (6, 1)ldint_mem과 다른 네 개의 벤치마크, 그리고 자기 자신과의 pair들이 우선순위 6,1로 실행 했을 때의 background thread의 평균이다. 일반적으로 high-latency thread는 가장 좋은 foreground thread, 가장 좋지 않은 background thread가 된다. 그리고 아주 좋은 성능을 갖는 thread는 다른 thread의 영향을 매우 쉽게 받기 때문에 background thread로서 적합하지 않다.




5.  Conclusion


이 논문에서는 SW-controlled prioritization mechanism의 효과를 알아보기 위해 프로세서의 특정 성격에 중점을 둔 마이크로 벤치마크의 집합을 사용하여 심도 깊은 평가를 수행하였다. 이로부터 얻은 결론은 다음과 같다. 첫째로 많은 양의 long-latency operation을 보이는 workload low-latency operation을 수행하는 것에 비해 우선 순위에 영향을 덜 받는다. 두 번째로 prioritization mechanism을 사용하여 매우 특별한 경우 두 배 이상의 전반적인 throughput이 향상될 수 있다. 그러나 이러한 극단적인 향상은 낮은 IPC를 갖는 thread의 성능이 대폭 감소함을 의미한다. 조금 덜 극단적인 경우로 40% 정도의 throughput 향상이 가능하다. 세 번째로 우선순위의 full spectrum을 사용하는 대신 +/-2까지 만을 사용하고, 둘 중 하나의 thread가 별로 중요하지 않을 경우에는 "extreme" 우선 순위를 사용한다.

우선 순위가 throughput 23.7%향상시키고 실행시간을 9.3%줄이며, background thread를 갖는 경우의 case study를 제시하였다. 마지막으로 POWER5 priority mechanism은 몇 가지 metric을 향상시키는 데 사용될 수 있는 매우 강력한 툴이라는 결론을 내린다. 이 연구는 HW resourcethread 간에 balancing하는 것을 더 효과적으로 하는 것을 허용하는 SW/HW c-design의 폭넓은 활용으로 가는 길을 열어 주었다.


저작자 표시 비영리 변경 금지
Creative Commons License
Creative Commons License

이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책과 각종 인터넷 자료를 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)


KMS와 Semantic Web(Ontology)

현재의 KMS는 키워드 기반의 검색을 제공하며, 관련있는 정보를 비교 검색하는 데 사람의 시간과 노력을 요구한다.또한 정보의 유지, 보수에 있어서, 용어의 불일치와 오래된 정보의 적절한 제거 정리가 잘 이루어 지지 않는다. 또한, 이러한 정보들을 이용해서 새로운 지식을 추론해 내는 것이 어렵다. 지식을 그 의미에 따라 개념적 공간에 표현한다.새로운 지식의 추출과 지식의 불일치를 검사하여 지식의 유지보수를 돕는다. 키워드 기반이 아닌 쿼리 기반의 검색을 제공한다. 사람에게 친숙한 방법으로 요구된 지식을 검색, 추출, 표현한다. 특정 정보에 대해 제한적 접근을 정의할 수 있다.시멘틱 웹의 핵심인 온톨로지는 특정 도메인 내에서 사용되는 용어와 그 관계를 정의한 것으로 지식 정보와 그 구조의 공통적 의미를 이해하고 공유하며,도메인 지식의 효과적인 재활용을 위해 필요하다. 이는 사람과 사람간의 이해와 지식 공유는 물론 기계가 이를 이해하고 공유할 수 있도록 함으로서, 지식정보가 공유되지 않음으로서 발생하는 소모적,반복적 재투자를 방지하고, 복잡하고 이질적인 정보 시스템의 효과적인 상호 운용과 표준화를 가능하게 한다.


Web2.0

인터넷에서 최근 몇년 간 발생한 웹 환경의 변화와 그 트렌드를 종합한 것으로, 1세대 웹의 흥망 이후에 살아남은 인터넷 서비스들이 공통적으로 갖는 특징들을 그 특성으로 갖는다. 웹은 하나의 플랫 폼으로서 사용자의 참여를 유도하며, 집단 지성의 활용과 확산, 사용자가 직접 창조한 컨텐츠와 서비스를 강조하고 사용자에게 다양한 경험을 제공하는 것 등이 그 큰 특징이라 하겠다. Web 2.0은 신디케이션과 메시징 기능으로 사회적 네트워크를 형성하며, 기존의 매체에 비해 상호 작용성을 높인다. 또한 새로운 BM모델로 새로운 사업 기회를 창출하고, 개인의 지식 정보의 공유가 활발해짐에 따라 기업 분위기가 활성화된다. 사용자의 적극적인 참여로 인한 사용자 중심의 언론 영향력이 증가하고, 지식의 보급과 형성이 중앙 집중적 방식에서 개인 기반 분산형으로 변화한다.


Semantic Web의 정의

시멘틱 웹은 웹 컨텐츠가 자연어 뿐만 아니라 소프트웨어 에이전트, 즉 기계가 읽고 사용할 수 있는 형태로 기술되어, 정보의 검색과 공유,통합을 더욱 쉽게 할 수 있도록 하는 WWW의 진보된 확장 개념이다. 데이터, 정보, 지식의 universal medium, 주어진 지식 도메인에서 개념(concept), 용어(terms), 관계(relationship)을 표현하기 위한 formal description을 제공하기 위해 RDF(resource description framework) 스키마와 OWL (web ontology language)등의 기술 언어와 다양한 데이터 교환 형식(RDF/XML, N-triples, N3, turtle등)을 포함한다.


collective intelligence

집단 지성은 사전적으로 다수의 개인들이 협업과 경쟁을 통해 모아지고 통합된 지성(intelligence)의 한 형태를 의미한다. 이는 사회학, 경제학, 컴퓨터 공학, 집단 행동등의 매우 다양한 분야의 하위 영역으로 연구될 수 있다. Web 2.0의 대두와 함께 그 주요한 특성의 하나로 주목받고 있는 집단 지성의 개념은 1세대 웹의 흥망 이후 살아남은 웹 기반의 서비스들이 공통적으로 갖는 핵심적인 원칙, 특징이기도 하다. 기존의 웹에 비해 시각적 부분과 상호 작용이 강화된 하나의 플랫폼으로서 사용자의 참여를 유도하고, 사용자는 이를 통해 더욱 강한 사회적 실재감을 느끼게 되며, 다양한 컨텐츠와 서비스를 창조한다. 이로서 사용자는 미디어로부터 수동적으로 정보를 얻는 소비자의 역할에서 나아가 정보를 생산하는 생산자의 역할을 동시에 담당하게 된다. 집단 지성을 이용한 대표적인 서비스의 예로, 다수 사용자의 citation정보를 이용한 pagerank알고리즘으로 효과적인 검색 결과를 제공하는 구글, 경매 방식을 이용하여 사용자의 참여를 유도한 이베이와 상품에 대한 사용자의 리뷰정보를 바탕으로 사용자에 맞는 상품의 검색을 용이하도록 돕는 아마존 등을 들 수 있다. 더 나아가 이러한 집단 지성, 즉 사용자의 참여를 위한 플랫폼만을 제공하여 큰 성공을 거둔 대표적인 서비스로는, 사용자들이 직접 제공한 정보들로 협업적으로 구성된 백과사전 wikipedia와 사진의 저장과 검색, 공유 서비스를 제공하는 flickr, 북마크의 공유와 검색을 돕는 delicious, 사용자가 제작한 동영상의 공유를 위한 youtube 등이 대표적이다. 사용자의 자발적인 참여로 지식이 증가, 단점은?


knowledge map in KMS

지식 맵은 조직이 갖고 있는 지식내역 및 상세설계내역의 체계적인 분류를 의미하며, 지식 분류체계, 지식명, 지식 설명 등으로 구성된다. 지식맵은 지식의 변화에 따라 지속적인 확인 및 보완이 필요하며, 이는 시스템적으로 유연한 분류 체계가 지원되어야 가능하다. 그러나 지식 맵의 구성이 아무리 잘 되어 있어도 가치있는 지식의 보관 및 활용이 원활히 이루어지지 않으면 소용이 없다. 지식 맵의 구성은 우선 조직의 핵심 업무에 맞는 목표 지식을 선정함으로서 범위를 구체화한다. 조직 전체의 지식 맵부터 설계하는 것이 아니라 단위별 핵심업무에 따른 의미있는 분류체계를 수립해야 한다. 분류 단계가 너무 많으면 사용들에게 혼란을 줄 수 있으므로 조직 전체 차원에서 2~3단계 정도가 적당하다.


knowledge representation in terms of frames

프레임은 인공지능 데이터 구조로서, 정형화된 상태, 혹은 상황(sterotyped situations)을 표현함으로서 지식을 그 하위 구조들로 나누는 데 사용된다. 프레임을 이용한 지식의 표현은 대략 객체 지향과 유사한 패러다임을 갖는데, 이는 사람이 어떤 지식을 저장하는 방법과 매우 유사하다. 프레임은 hierarchy를 갖으며, 가장 일반적인 개념을 기술하는 프레임이 가장 상위의 프레임이 될 수 있고, 하위 프레임은 상위 프레임의 다중 상속이 가능하다.각 프레임(class)은 그 이름과 속성집합으로 이루어져 있다., 집이라는 프레임은 색상, 층 수 등의 속성을 갖을 수 있다. 예를 들어프레임의 속성 값들은 사람이 일반적으로 이미 알고 있는 사실을 기반으로 하는 내정값을 갖는다. 예를 들어, 어떤 사람이 “아이가 공을 찬다”라고 말할 때, 대부분의 사람들은 아무런 특징을 갖지 않는 추상적인 공의 형태를 상상하기 보다는 특정한 공의 형태,. 즉 마치 축구공과 유사한 공을 시각화하여 생각할 수 있다프레임 구조는 도식적인 지식의 표현이나 전형적인 인지패턴 등을 표현하는데 매우 효과적이다.


define the ontology in semantic web

온톨로지는 주어진 특정 도메인 내에서 정보의 교환을 목적으로 합의된 어휘를 만들기 위해 개념, 개념간의 관계를 표현하는 데이터 모델이다. 온톨로지는 일반적으로 도메인 내의 개념(클래스), 개념의 속성, 개념간의 관계를 표현하는데, 도메인 내의 객체에 대한 추론을 위해 사용된다. 웹 온톨로지는 시멘틱 웹의 핵심적인 개념으로, 웹 문서를 생성하는 마크업 언어에서 정의된 동일 의미의 다른 명칭 식별자(태그) 또는 같은 내용을 다른 구조로 정의하는 식별자 등에 의해 발생되는 호환상의 문제를 해결 하기 위해 공유되는 개념화를 정형적, 명시적으로 명세화한 집합체이다. 즉, 웹에 의미(Semantic)를 부여한다는 것, 웹 컨텐츠를 사람 뿐 아닌 기계도 읽고 이해할 수 있도록 하는 것, 의미론적 마크업 언어 사용 (RDE, OWL..)


difference between conventional web and semantic web

기존의 웹은 마크 업 언어를 이용하여 자연어 텍스트나 그래픽, 멀티미디어, 페이지 레이아웃 등을 사용자에게 보여주는 형식으로, 사람은 눈에 보여지는 내용을 읽고 이해할 수 있으며 이미지 등에서 의미를 이끌어 낼 수 있다. 즉, 기존의 웹는 단순이 데이터를 사용자에게 보여줄 뿐, 이 데이터와 정보를 이해하고 통합하여 유용한 지식을 얻는 과정은 사람이 직접 수행해야 한다. 시멘틱 웹에서는 데이터의 의미를 기계가 이해할 수 있게 됨에따라, 다양한 소스로부터의 데이터의 수집과 이를 통해 새로운 결론을 이끌어 내는 과정을 사람이 아닌 기계에 의해 가능해진다. 정보와 그 내용을 연결함으로서 정보의 유용성이 증대되므로, 개인은 물론 조직의 관점에서 데이터의 효과적인 관리와 재사용이 가능해진다. 첫째로 정보를 검색할 때 요구하는 보다 정확한 결과를 가져오며, 둘째, 서로 다른 이형질 소스의 정보를 통합하고 비교가 가능하고, 셋째,어떤 리소스에 대해서도 의미적이고 기술적인 정보를 연관시킨다.마지막으로 웹 서비스의 자동화를 위해 웹에 세부 정보를 첨가시킬 수 있는 특징으로 요약 할 수 있겠다.


How Semantic web impact on traditional electronic commerce?

만 약에 전자상거래에 시맨틱 웹을 적용한다면 기존 웹을 통해 할 수 없던 많은 일을 자동적으로 처리할 수 있는데 지금까지는 구매자가 인터넷 쇼핑몰을 찾아다니면서 상품을 눈으로 보고 선택해 구매하는 것이 일상적인 형태였으나 시멘틱 웹 기술은 각 인터넷 쇼핑몰에서 눈으로 보여주기 위한 상품정보 뿐 아니라 제품 규격·거래 조건 등에 대한 메타정보가 같이 제공되어 컴퓨터가 사람을 대신해 원하는 제품의 검색뿐 아니라 가격협상까지 할 수 있게 된다. 또한 생산, 판매, 배송, 사용자의 피드백 과정에서 발생하는 정보를 통합 관리함으로서 비지니스 프로세스의 자동화에 기여할 수 있다.


Rete Algorithm

expert system의 기초가 된 알고리즘인 Markov 알고리즘의 발달된 형태로, markov알고리즘은 룰에 우선수위를 두어 높은 우선순위의 룰을 먼저 시행하는 제어 전략을 세운 것인데, 실세계의 문제를 해결하기 위해서는 수많은 룰을 실행해야 하기 때문에 효율성에 문제가 제기되었다. Rete algorithm 은 network 상에 rule 에 관한 정보를 저장함으로써 속도를 향상시키는 very fast pattern matcher 이다. 모든 rule 에 대한 facts 를 match 시키는 것이 아니고, 변화된 facts 에 대해서만match 시킨다. 각 cycle에서 변화가 없었던 static data 는 무시되기 때문에matching 속도를 크게 향상시킨다.


Human Knowledge를 First order logic으로 표현할 경우에 장단점

장점 : Propositional logic에 비해 표현력이 좋다.
단점 : Knowledge는 complete 해야 한다.
Knowledge는 일관성이 있어야 한다. (지식들 간의 conflict가 없어야 한다.)
Knowledge base는 monotonic하게 증가해야 한다. 즉, 새로이 추가되는 Knowledge에 의해 이미 Knowledge base내에 구축되어 있는 Knowledge는의 변경이 없어야 한다.

Consider the following argument:

1. Everyone who is married either has a husband or has a wife.

2. Jack is married.

3. Jack does not have a husband.

We may conclude that

4. Jack has a wife.

a) Rewrite the premises and conclusion in predicate calculus using the following symbols:

M(x)x is married

H(x,y)x has husband y

W(x,y)x has wife y

b) Convert these formulas to clause form using f, g, h,... for Skolem functions.

c) Verify this argument by displaying a resolution proof.

a) (∀x)(M(x)H(x,y)W(x,y))b)(x)(M(x)(H(x,y)W(x,y)))

M(Jack)(x)(¬M(x)(H(x,y)W(x,y)))

H(Jack)¬M(x)H(x,y)W(x,y)

W(Jack, y)M(x1)

H(x2, y1)

W(x3, y2)


The predicate logic : An example

1. Man(Marcus)

2. Pompeian(Marcus)

3. ¬Pompeian(x1) Roman(x1)

4. Ruler(Caesar)

5. ¬Roman(x2) Loyalto(x2, Caesar) ∨ Hate(x2, Caesar)]

6. Loyalto(x3, f(x3))

7. ¬Man(x4) ∨ ¬Ruler(y1) ∨ ¬Tryassassinate(x4, y1) ∨ ¬Loyalto(x4, y1)

8. Trytoassassinate(Marcus, Caesar)

Hate(Marcus, Caesar)

1.JPG





CWA vs OWA and ontology

CWA은 지금까지 true로 알려지지 않은 것은 false라는 가정이다. 이에 반대되는 개념으로 지식의 불충분함이 false를 의미하는 것은 아니라는 가정의 OWA이다. KM분야에서, KB가 완전할 때, 예를 들어 모든 고용인의 정보가 포함된 회사의 DB, 또는 KB가 완전하지는 않지만, 가장 결정적인 응답을 이끌어낼 수 있는 경우 사용한다.
다음 의 예시를 보면, 누가 Formal logic을 editing하지 않았는가? 라는 쿼리에 대해 CWA에서는 Sarah Johnson이라는 답을 얻을 수 있다. 그러나 OWA의 경우, 답은 알 수 없다. 다음 tuple이 모든 정보를 표현하고 있다고 볼 수 없기 때문이다.
John Doe, Formal Logic
John Doe, Closed World Assumption
Joshua A. Norton, Formal Logic
Sarah Johnson, Introduction to Spatial Databases
Charles Ponzi, Formal Logic
Emma Lee-Choon, Formal Logic

그러나 다음 경우를 보자. {English(Fred) V Irish(Fred)} 라는 KB가 있을 때, CWA하에서는 이 정보만으로는 Fred가 영국인인지 아이리쉬인지 증명할 수 없다. (┐English(Fred)나 ┐Irish(Fred) 로 nothing을 얻을 수 없다.) 때문에 ┐English(Fred)과 ┐Irish(Fred) 는 true이므로 KB에 포함되고, 결국 정보의 inconsistency가 발생한다.
그 렇다면 온톨로지는 어떤 Assumption을 사용해야 하는가. 답은 둘 다, 여러 도메인이 양면을 모두 포함하기 때문이다. 우선 실세계의 모든 도메인에서 불완전한 정보를 다루고 있다는 데서 OWA이 더욱 자연스럽다. 무엇보다 추론의 경우, 온톨로지에 없는 새로운 지식을 이끌어낸다는 점에서도 OWA에 맞다. 또한 지식을 재사용, 확장하거나, 스키마와 스키마 간의 매핑, 여러개의 이름을 갖는 하나의 사물을 표현하는데에도 OWA여야한다. 그러나 제약조건을 만들거나, 정보를 validation할 때, 즉, 스키마와 데이터 간의 매핑을 할 때는 OWA를 사용할 수 없다. data structure등과 같이 전형적으로 closed된 것이나, 전통적으로 closed된 문제들, 유한한 원소들을 다루거나 "...가 아닌것은 무엇인가?"등의 문제는 CWA일 경우 더 좋다.


RDF

RDF는 오브젝트와 그들 사이의 관계를 표현하기 위한 데이터 모델이다. RDF 스키마는 어휘 기술 언어로서, RDF 리소스의 클래스와 프로포티를 기술한다. 클래스와 프로퍼티의semantic과hierarchy 를 제공하고, 기본적인 표현 단위는object-attribute-value의triple이다.



     
          
               David Billington
          
     


OWL

더욱표현이풍부한온톨로지언어이다. 클래스간의관계, 다양한프로퍼티의타입과성질등을표현한다. OWL Full is so powerful that it is undecidable (No complete (or efficient) reasoning support). OWL DL (Description Logic) is a sublanguage of OWL Full that restricts application of the constructors from OWL and RDF. An even further restriction limits OWL DL to a subset of the language constructors (E.g., OWL Lite excludes enumerated classes, disjointness statements, and arbitrary cardinality). The advantage of this is a language that is easier to grasp, for users implement, for tool builders. The disadvantage is restricted expressivity.



     An example OWL ontology
     
     
          University Ontology
     

이 글은 스프링노트에서 작성되었습니다.

저작자 표시 비영리 변경 금지
Creative Commons License
Creative Commons License

이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)

Advanced Memory Hierarchy

  • Review: 6 basic cache optimizations
    • Giving reads priority over writes
    • Avoiding adress translation during cache indexing
    • multilevel cache
    • larger block size(compulsory misses)
    • larger cache size(capacity misses)
    • higher associativity(conflict misses)
  • 11 advanced cache optimizations
    • Fast hit time vs. small and simple caches

      메모리 크기가 작으면 인덱싱하는데 시간이 적게 걸리므로 작은 캐시는 hit time을 줄일 수 있다.

      simple: direct mapping

    • Fast hit time vs. way prediction

      hit time이 빠른 direct napped cache와 conflict miss가 적은 2way set associativity cache를 어떻게 혼합할까?

      way prediction: 캐시 내의 여분의  bit을 두어 "way"를 예측한다. set안의 블럭, 다음 캐시 접근 등

    • fast hit time vs. trace cache

      더 많은 ILP 찾기

      메모리의 레이아웃에 의해 결정되는 고정적인 인스트럭션의 순서가 아닌 실행된 인스트럭션의 dynamic trace

      긴 블럭의 경우에 더 좋다. 블럭의 중간에서 나가거나 들어오지 않는다.

      주소가 더이상 2의 워드 크기의 거듭제곱꼴로 정해지지 않기 때문에 주소 매핑이 복잡하다.

      서로 다른 브랜치 결과때문에 여러 dynamic trace에 인스트럭션들이 여러 번 나올 수 있다.

    • increasing cache bandwidth by pipelining

      파이프라인 캐시 접근은 BW를 보장하지만 latency가 크다.

      브랜치 예측 미스에 대한 penalty가 크다,

      load의 issue와 데이터의 사용 사이에 더 많이 사이클이 생긴다.

    • increasing cache bandwidth: non-blocking cache

      미스된 동안에도 데이터 캐시가 계속해서 캐시 힛을 제공하도록 하는 캐시이다; 레지스터에 F/E bit, out-of-order execution, multi-bank memory가 요구된다.

      미스를 수행하는 동안에 hit을 제공하면 유효 마스페널티가 줄어든다.

      다중 미스 중 힛, 미스 중 미스,의 경우 여러개의 미스가 오버랩되므로 유효 미스 패널티는 훨씬 낮다.

      캐시 컨트롤러의 복잡도는 증가, 다중 뱅크 메모리 필요

    • increasing cache BW via multiple banks

      여러 독립적인 뱅크로 나누는 것이 동시 접근을 지원하기에 좋다.

      접근이 뱅크에 자연스럽게 분포되어 있을때 가장 성능이 좋다. -> 즉, 주소의 매핑이 메모리 시스템의 행동에 영향을 준다. 성늘이 좋은 단순한 매핑은 'sequential interleaving'

    • reduce miss penalty: early restart and critical word first

      CPU를 재시작하기 전에 full block을 대기하지 않는다.

      early restart: 요청한 블럭의 워드가 도착하자마자 CPU로 보내고 CPU가 실행을 계속하도록 한다.

      critical word first: 메모리로부터 미스된 워드를 먼저 요청하여, 도착하자마자 CPU로 보낸다. 블럭의 남은 워드를 다 채울동안 CPU는 실행을 계속한다.

    • merging write buffer to reduce miss penalty

      쓰기버퍼는 메모리에 쓰는 것을 대기하는 동안에도 프로세서가 동작하도록 한다.

      버퍼가 수정된 블럭을 갖는다면, 새로운 데이터가 적합한 쓰기 버퍼 엔트리의 주소와 맞는지를 보기위해 그 블럭의 주소를 체크한다. 엔트리가 맞으면, 새로운 데이터는 그 엔트리와 합쳐진다.

      multiword writes는 메모리에 더 효율적이기 때문에 sequential word, byte의 쓰기를 위한 write-through cache의 write의 block size를 증가시킨다.

    • reducing misses by compiler optimization

      instructions: conflict miss를 줄이기 위해 메모리에서 프로시져를 재구성한다. conflict를 프로파일링

      data: merging array: 엘리먼트를 합친 단일 배열은 두 개의 배열보다 spatial locality를 향상시킨다.

      loop fusion: 같은 루핑, 일부 변수의 오버랩이 있는 두 개의 독립적인 루프를 조합

      loop interchange: 메모리에 저장된 순서대로 데이터를 접근하도록 중첩된 루프를 변경

      blocking: 데이터의 "blocks"를 반복적으로 접근하게 함으로서 temporal locality를 증가시킨다.

      • merging array //val과 key의 conflict를 줄이고 spatial locality증가시킨다.

        /* Before: 2 sequential arrays */
          int val[SIZE];
          int key[SIZE];
        /* After: 1 array of stuctures */
        struct merge {
          int val;
          int key;
        };
        struct merge merged_array[SIZE];

      • loop interchange // striding하지 않고 매 100 word를 순차적으로 접근

        /* Before */
        for (k = 0; k < 100; k = k+1)
          for (j = 0; j < 100; j = j+1)
             for (i = 0; i < 5000; i = i+1)
                x[i][j] = 2 * x[i][j];
        /* After */
        for (k = 0; k < 100; k = k+1)
          for (i = 0; i < 5000; i = i+1)
             for (j = 0; j < 100; j = j+1)
                x[i][j] = 2 * x[i][j];

      • loop fusion // a, c에 접근할 때 두 개의 미스가 발생하던 것을 하나로 줄임.

        /* Before */
        for (i = 0; i < N; i = i+1)
          for (j = 0; j < N; j = j+1)
             a[i][j] = 1/b[i][j] * c[i][j];
        for (i = 0; i < N; i = i+1)
          for (j = 0; j < N; j = j+1)
             d[i][j] = a[i][j] + c[i][j];
        /* After */
        for (i = 0; i < N; i = i+1)
          for (j = 0; j < N; j = j+1)
             { a[i][j] = 1/b[i][j] * c[i][j];
               d[i][j] = a[i][j] + c[i][j];}

      • blocking

        /* Before */
        for (i = 0; i < N; i = i+1)
          for (j = 0; j < N; j = j+1)
             {r = 0;
                for (k = 0; k < N; k = k+1){
                   r = r + y[i][k]*z[k][j];};
                   x[i][j] = r;
             };

        z의 N*N element를 모두 read, 반복적으로 y의 첫 row의 N element를 read, x의 첫 row의 N element에 write

        2N^3 + N^2만큼의 capacity miss ==> B* B의 submatrix로 계산

        /* After */
        for (jj = 0; jj < N; jj = jj+B)
        for (kk = 0; kk < N; kk = kk+B)
        for (i = 0; i < N; i = i+1)
          for (j = jj; j < min(jj+B-1,N); j = j+1)
             {r = 0;
                for (k = kk; k < min(kk+B-1,N); k = k+1) {
                   r = r + y[i][k]*z[k][j];};
                x[i][j] = x[i][j] + r;
        };

        B는 blocking factor, capacity miss는 2N^3/B + N^2으로 감소

       

    • reducing misses by hardware prefetching of instructions & data

      prefetching은 페널티 없이 사용될 수 있는 여유의 메모리 BW가 있는가에 의존한다.

      instruction prefetching: 일반적으로 CPU는 미스에서 두 개의 인스트럭션을 fetch하는데, 요청된 블럭과 연속된 다음 블럭이다. 값이 리턴될때 요천블럭은 인스트럭션 캐시에, prefetch된 인스트럭션은 인스트럭션 스트림버퍼에 위치한다.

      data prefetching: 두개의 연속적인 L2 캐시 미스가 발생하고, 두 캐시블럭의 거리가 256 byte이하이면 prepetching된다.

       

    • reducing misses by software prefetching data

      레지스터나 캐시에 prefetch, prefetching instruction은 speculation execution의 형태로 falut를 일으키지 않는다. prefetching instruction을 issue하는데 시간이 걸리지만, miss를 줄여서 얻는 이익보다 작다. issue BW를 줄이려면 higher superscalar

       

  • Virtual machine
    • Java VM과 같은 표준 SW interface를 제공하는 모든 emulation method를 포함한다. 시스템 가상 머신은 binary ISA에서 완전한 시스템레벨 환경을 제공한다.하나의 컴퓨터는 여러 가상머신을 돌릴수있고 서로 다른 여러 OS를 지원한다. underlying HW platform은 host, guest VM들 사이에서 HW의 리소스를 공유한다.
    • vitrual machine monitor

      hypervisor하고도 하며, VM을 지원하는 소프트웨어이다. 가상 리소스와 물리적 리소스를 어떻게 매핑할 것인지 결정한다. 전통적인 OS에 비해 훨씬 규모가 작다.

    • VMM overhead

      workload에 따라 다르다. user-level processor bound program은 가상화 오버헤드가 없다. I/O intensive workload => OS intensive는 많은 시스템 콜과 privileged 된 인스트럭션이 수행되기 때문에 높은 가상화 오버헤드가 야기된다.  I/O intensive workload가 I/O bound라면 I/O를 기다리는 동안 프로세서 사용도가 낮고, 프로세서의 가상화가 hidden, 가상화 오버헤드가 작다.

  • requirements of a virtual machine monitor
    • VMM은 guest SW에게 SW interface를 보여주어야 한다. 게스트의 상태를 각각 독립시켜야 한다. 게스트 소프트웨어로 부터 자신을 보호해야 한다.
    • 게스트 SW는 원래의 HW에서 동작하는 것과 똑같이 VM에서 동작해야 한다. 성능 관련 동작, 여러 VM이 공유해야 하는 고정 리소스에 대한 제한 등의 경우 예외
    • 게스트 SW는 실제 시스템 리소스의 할당을 변경할 수 없다.
    • VMM은 게스트 VM과 OS가 일시적으로 사용한다 하더라도 거의 모든 것을 제어해야 한다.
    • VMM은 게스트 VM보다 높은 선점권을 가져야 한다. 타이머 인터럽트의 경우, VMM은 현재 실행중인 게스트VM을 중지시키고 상태를 저장하고 인터럽트를 핸들하고 다음 실행할 게스트 VM을 결정하고 그 상태를 로드한다. 게스트 VM은 가상 타이머에 의해 제공된 타이머 인터럽트에 관여된다.
  • ISA supports for VM
    • ISA를 설계할 때 VM이 계획된다면 VMM에 의해 실행되어야 하는 인스트럭션을 줄이기 쉽고, 이를 에뮬레이트하는데 얼마나 시간이 걸리는가를 알기 쉽다.
    • VMM은 게스트 시스템이 오직 가상 리소스와 상호작용하는것을 보장해야 한다. conventional guestOS는 user mode로 VM의 최상위에서 동작한다. 게스트 OS가 HW 리소스와 관련된 정보를 수정하려고 시도하면 이는 VMM으로 넘어간다.
    • 그렇지 않은 경우, VMM은 이 인스트럭션을 가로채서 정보의 가상버젼을 게스트 OS에 제공한다.
  • impact of VMs on virtual memory
    • VMM은 real memory와 physical memory를 나눈다. real memory는 가상 메모리와 물리적 메모리의 중간단계이다. machine memory라고도 한다. 게스트 OS는 자신의 페이지 테이블에 가상 메모리와 real memory를 매핑하고, VMM 페이지테이블은 real memory와 physical memory를 매핑한다.
    • VMM은 shadow page table을 유지하는데 이는 virtual memory와 physical memory를 직접 매핑한다.
  • ISA support for VMs & virtual memory
    • sw TLB를 virtualize하기 위해 VMM은 real TLB와 게스트 VM의 TLB의 내용의 카피를 갖는다. TLB에 접근하는 어떤 인스트럭션도 trap된다. 프로세스 ID tag를 갖는 TLB는 전체 서로다른 VM과 VMM의 mix를 지원하기때문에 VM이 스윗치될때 TLB를 flushing하는것을 피할 수 있다.
  • Impact of I/O on virtual memory
    • 가장 어려운 virtualization이다. 컴퓨터에 추가되는 I/O device의 종류나 수가 증가하였고, 여러 VM들이 I/O device를 공유하고, 디바이스 드라이버 또한 무수히 많다.
    • I/O device driver의 각 타입의 일반적인 VM버전을 제공하고, VMM이 real I/O를 다루도록한다.
    • 가상 I/O device와 physical device의 매핑 방법은 디바이스의 타입에 따라 다르다.

이 글은 스프링노트에서 작성되었습니다.

저작자 표시 비영리 동일 조건 변경 허락
Creative Commons License
Creative Commons License

이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)

Directory based Multiprocessor

  • cache coherent system must:
    • states, state transition diagram, action을 제공
    • coherence protocol 관리

      프로토콜이 언제 invoke될 것인지 결정

      액션을 결정하기 위해 다른 캐시의 블럭의 상태에 대한 정보를 찾는다. >> 다른 캐시 카피와 communication할 것인가 결정

      locate the other copies

      communicate with those copies(invalidate/update)

    • 프로토콜의 invoke는 모든 시스템에서 같은 방법으로 이루어지는데, 라인의 상태가 캐시에 유지되고, 라인에서 access fault가 일어나면 프로토콜이 invoke된다.
    • 프로토콜의 접근방법 차이는 다른 캐시블럭 상태 정보를 찾고, 다른 캐시 카피와 communication하는 방법의 차이이다.

       

  • Bus based coherence
    • 캐시카피상태정보를 찾고 액션을 결정하고 통신하는 일련의 과정이 모두 버스의 broadcasting에 의해 이루어진다. 스케일이 큰 네트워크에서도 개념적으로 가능하지만, 버스BW와 트래픽때문에 실제로는 어렵다. 때문에 통신을 줄이면서 같은 프로토콜을 다룰 수 있는 메커니즘 필요

       

  • Scalable approach: directories
    • 모든 메모리 블럭은 연관된 디렉토리 정보를 갖는다. 캐시된 블럭의 카피와 그 상태를 계속해서 유지한다. 미스가 발생하면 디렉토리 엔트리를 찾아 look up하고 필요하다면 오직 그 카피를 갖는 노드와 통신한다. 대규모의 네트워크에서 디렉토리와 카피와의 통신은 네트워크 트랜잭션을 통해 이루어진다. 디렉토리 정보를 구성하는 여러가지 방법론이 존재한다.

       

  • Basic operation of directory
    • k processors, 메모리 내의 각 캐시 블럭은 k presence-bit, 1 dirty bit를 갖는다. 캐시내에 있는 각 캐시 블럭은 1 valid bit, 1 dirty (owner) bit를 갖는다.

      6.jpg

    • processor i에 의한 메인 메모리로부터의 read:

      if dirty-bit is OFF then {메인 메모리로부터 읽기; p[i] ON;}

      if dirty-bit is ON then {dirty processor로부터 라인을 리콜한다(캐시 상태를 shared로); 메모리 갱신; dirty-bit OFF; p[i] ON; 리콜된 데이터를 i에 제공한다;}

    • processor i의 메인메모리에 쓰기

      if dirty-bit is OFF then {i에 데이터 제공; invalidation을 그 블럭을 갖는 모든캐시에 보낸다; dirty-bit ON, p[i] ON;...}

       

  • Directory protocol
    • snoopy protocol과 유사한 세 가지 상태

      shared: 1개 이상의 프로세서가 데이터를 갖고 있다, 메모리는 최신상태

      uncached: 어떤 프로세서도 데이터를 가지고 있지 않으며, 어떤 캐시도 valid하지 않다.

      exclusive: 1개 프로세서(owner)만 데이터를 가지고 있다. 메모리는 out-of-date상태

    • 캐시의 상태와 함께 shared state일 때 어떤 프로세서가 데이터를 소유하고 있는지 트랙해야 한다. (일반적으로 프로세서가 데이터를 가지고 있으면 bit vector가 1이다.)
    • 간단히...non-exclusive data에 쓰기시도는 쓰기 미스, 접근이 완료될 때까지 프로세서는 블럭됨, 메시지는 보내진순서대로 받아지고 행해진다.
    • 버스가 없고 브로드캐스팅 하지 않는다. interconnection은 더 이상 하나의 중재적 위치가 아니다. 모든 메시지는 명시적인 응답을 받는다.
    • 일반적으로 3개의 프로세서가 포함된다.  

      Lacal node: 리퀘스트가 발생한 노드

      home node: 주소가 존재하는 메모리 로케이션

      remote node: exclusive 하거나 shared한 캐시블럭의 카피를 갖는 노드

  • directory portocol messages
    • Read miss: local cache -> home directory (P,A); 프로세서 P가 A 주소에서 읽기 미스, 데이터를 요구하고 P를 읽기 공유자로 한다.(read shared)
    • Write miss: local cache -> home directory (P,A); 프로세서 P가 A 주소에서 쓰기 미스, 데이터를 요청하고 P를 배타적 소유자로 한다. (exclusive owner)
    • Invalidate: local cache -> home directory (A); 주소 A의 블럭을 캐싱하고 있는 모든 리모트 캐시에 invalidate를 보낼 것을 요청
    • Invalidate: home directory -> remote cache (A); 주소 A의 데이터의 공유된 카피를 invalidate
    • Fetch: home directory -> remote cache (A); 주소 A의 블럭을 패치하고 그 블럭을 홈 디렉토리로 보낸다. 리모트 캐시에 있는 A의 상태를  shared로 변경한다.
    • Fetch/Invalidate: home directory -> remotoe cache (A); 주소 A의 블럭을 패치하고 그 블럭을 홈 디렉토리로 보낸다, 캐시의 블럭을 invalidate한다.
    • Data value reply: home directory -> local cache (D); 홈 메모리로부터 데이터 값을 리턴
    • Data write back: remote cache - > home directory (A,D); 주소 A 에 데이터 값을 WB

       

  • State transition diagram
    • state는 스누피 프로토콜과 같고, 트랜지션도 유사, 읽기미스, 쓰기미스, invalidate, data fetch의 리퀘스트에 의해 트랜지션된다. 홈 디렉토리로 읽기미스, 쓰기미스 메시지가 생성되어 보내진다. 읽기미스 발생시 스누핑에서처럼 브로드캐스팅하는 것이 아니가 명시적인 invalidate와 data fetch요청이 이루어진다.

      7.jpg

    • 모든 개별 캐시에 대한 state와 트랜지션 다이어그램은 같다. 디렉토리 스테이트의 갱신과 리퀘스트를 만족시키는 메시지를 보낸다. 메모리 블럭의 모든 카피를 트랙킹한다. sharing set과 sharer의 갱신 액션도 지시한다.

      8.jpg

  • Example directory protocol
    • 디렉토리로 보내지는 메시지는 , 디렉토리의 갱신, 리퀘스트를 만족시키기 위한 메시지, 두 액션에 의해 발생한다.
    • Uncached상태의 블럭: 메모리의 카피가 현재 값, 이 블럭에 대해 가능한 리퀘스트는

      읽기미스: 요청하는 프로세서가 메모리로부터 데이터를 받는다. 요청자는 sharing mode만 될 수 있다. 블럭의 상태는 shared가 된다.

      쓰기미스: 요청하는 프로세서는 값을 받고, sharing mode가 된다. 블럭은 vaild한 카피만을 캐시한 것을 알리는 exclusive상태가 되고, 공유자는 소유자의 아이덴티티를 표시한다.

    • shared상태의 블럭: 메모리의 값이 최신상태이다.

      읽기미스: 요청하는 프로세서는 요청한 데이터를 메모리로부터 받고, 공유자 셋에 추가된다.

      쓰기미스: 요청하는 프로세서는 값을 받는다. 공유자 셋에 있는 모든 프로세서는 invalidate메시지를 받는다. 공유자 셋은 이 요청 프로세서의 아이덴티티를 포함한다. 블럭의 상태는 exclusive가 된다.

    • exclusive상태의 블럭: 블럭의 현재 값은 공유자 셋에 의해 표시되고 있는 프로세서(소유자)의 캐시에 유지되어 있다.

      읽기미스: 소유자는 데이터 페치 메시지를 받는다. 이 메시지는 소유자의 캐시에 있는 블럭의 상태를 shared 상태로 전환되도록 하고, 소유자가 데이터를 메모리에 쓰여질 수 있도록 디렉토리로 보내도록 하는 역할을 한다. 요청 프로세서의 아이덴티티는 공유자 셋에 추가되고 소유 프로세서의 아이덴티티도 여전히 포함되어 있다.

      data WB: 소유 프로세서는 블럭을 교체하고, 이 블럭은 WB된다. 이 WB은 메모리 카피를 최신으로 만들고(홈 디렉토리가 소유자가 된다) 블럭은 이제 uncached가 된다. 공유자 셋은 비워진다.

      쓰기미스: 블럭은 새로운 소유자를 갖는다. 이전의 소유자에게 메시지가 보내지는데, 캐시는 블럭을 invalidate하고 , 새로운 소유자가 될 요청 프로세서로부터 온 값을 디렉토리에 보낸다. 공유자는 새로운 소유자의 아이덴티티를 셋하고 블럭은 exclusive상태를 유지한다.

      9.jpg 10.jpg 11.jpg 12.jpg 13.jpg 14.jpg

  • Syncronization
    • 공유데이터를 이용하는 서로 다른 프로세서가 언제 안전하게 사용할 수 있는 지를 알기위해 동기화한다.
    • HW primitive를 이용한 동기화 구현

      atomic exchange: 메모리에 있는 값을 위해 레지스터의 값을 변경한다. 0 => 동기화 변수 free, 1=> 동기화 변수 locked, unavailable, 프로세서는 lock하기를 원하는 메모리 주소를 갖는 레지스터의 lock변수를 1로 변경하려고 시도, 이미 다른 프로세서가 lock하고 있으면 1 리턴, 아니면 0; 동시에 발생하는 키교환 요청은 write serialization에 의해 순서결정

      test and set: 테스트를 통과하는 값을 셋팅,

      fetch and increment: memory location의 값을 리턴하고 자동적으로 증가시킨다.

    • single atomic memory operation의 구현은, 하나의 uninterruptible instruction에서 읽기/쓰기를 동시에 요구(0/1의 교환)하기때문에 문제가 생긴다. 하드웨어가 읽기/쓰기 연산 사이에 다른 어떤 연산도 허용하지 않기 때문에 coherence의 구현을 복잡하게 만들 수 있다.
    • 대안: 한 쌍의 인스트럭션이 atomic, 모든 다른 오퍼레이션이 이 한쌍의 오퍼레이션 전후에 발생하는 어떤 프로세서에 의해서도 실행되는 것처럼 나타날때 두 인스트럭션이 효율적으로 atomic하다. 두 인스트럭션이 atomic하면 다른 어떤 프로세서도 이 둘 사이의 값을 변경할 수 없다.

      load linked

      store conditional: 성공->1, 실패->0

      같은 주소에서 발생한 SC가 일어나기 전에 LL로 지정된 메모리 위치의 내용이 변경된다면, SC는 fail한다. 프로세서가 두 인스트럭션 간의 context switch하지 않으면, SC fail

      • atomic swap
      • try: mov R3,R4 ; mov exchange value
        ll R2,0(R1) ; load linked
        sc R3,0(R1) ; store conditional
        beqz R3,try ; branch store fails (R3 = 0)
        mov R4,R2 ; put load value in R4
      • fetch and increment
      • try: ll R2,0(R1) ; load linked
        addi R2,R2,#1 ; increment (OK if reg–reg)
        sc R2,0(R1) ; store conditional
        beqz R2,try ; branch store fails (R2 = 0)
    • Implementing locks using coherence

      spin locks: 프로세서가 lock을 얻는 것을 성공할때까지 loop의 주위를 spinning하면서 계속적으로 lock을 얻기를 시도. lock을 유지하느 시간이 짧고, locking latency가 작은 경우에 사용.

      li R2, #1

      lockit:  exch R2,0 (R1) ;atomic exchange

      bnez R2,lockit ;already locked?

    • exchange는 모든 카피를 invalidate하는 write를 포함하기 때문에, 버스 트래픽이 커진다. 변수를 단순히 반복적으로 읽는 것으로 시작해서, 변경죄면 exchange를 시도한다.

      try: li R2,#1
      lockit: lw R3,0(R1) ;load var
      bnez R3,lockit ;≠ 0 ⇒ not free ⇒ spin
      exch R2,0(R1) ;atomic exchange
      bnez R2,try ;already locked?





  •  

이 글은 스프링노트에서 작성되었습니다.

저작자 표시 비영리 동일 조건 변경 허락
Creative Commons License
Creative Commons License

이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)

SMP

  • MP motivation
    • uniprocessor 발달의 둔화는 ILP의 효과를 떨어뜨리고, power의 소비에 관련된 관심이 증가하면서 멀티 프로세서의 연구가 주요 이슈로 등장, 이러한 트렌드를 더욱 뒷받침하는 몇가지 요인을 살펴보면,

      data-intensive application의 증가

      server와 server performance에 대한 관심 증가

      데스크탑의 성능에 대한 중요성 감소 (이미 충분히 쓸만하게 빨라서?)

      어떻게 멀티프로세서를 효율적으로 사용할 것인가에 대한 이해 증진, 특히 자연적인 Tread-level prarllelism이 큰 서버 환경에서

      유니크한 디자인보다는 복제에 의한 디자인의 투자가 더 이익

       

  • Flynn's taxonomy
    • SISD: uniprocessor
    • SIMD: single PC(vector) => data level parallelism
    • MIMD: clusters, SMP servers => Thread level parallelism

      flexible, cost-effective

       

  • 메모리의 구성과 interconnection 기법에 따른 프로세서의 갯수와 관련된 MIMD의 두개의 class(parallel architecture = computer architecture + communication architecture)

    1.jpg

    • centralized shared memory multiprocessor

     100개 이하의 프로세서, 단일 중앙 집중적 메모리를 공유하기에 충분하게 작아야한다.

    symmetric multiprocessor라고도 하는데, 한 개의 메인 메모리가 모든 프로세서와 대칭관계이다.

    단일 메모리가 비교적 적은 수의 프로세서의메모리 요구를 만족시키기 위해 큰 캐시가 필요

    많은 메모리 뱅크와 스위치를 이용하여 수십여개(a few dozen)의 프로세서를 사용할 수 있다.

    기술적으로 가능한 한 많이 늘린다 하더라도, 중앙의 메모리를 공유하는 프로세서의 갯수가 늘어날 수록 비효과적이다.

    2.jpg

    • physically distributed memory multiprocessor

      많은 수의 프로세서 칩 연결 가능, 프로세서에 메모리가 분산되기 때문에 큰 bandwidth가 요구

      대부분의 access가 local memory라고 한다면, 메모리 bandwidth를 늘리는 cost-effective한 방법이다.

      local memory access의 latency를 줄일 수 있다.

      프로세서 간의 통신이 복잡하다.

      증가된 BW의 이익을 얻을 수 있도록 소프트웨어를 변경해야 한다.

       

  • communication과 memory architecture에 따른 두가지 모델
    • message-passing multiprocessors: 프로세서 간의 명시적인 메시지 교환에 의해 communication
    • shared memory multiprocessors: 공유된 주소 공간을 통해서 communication, 서로 다른 프로세서의 같은 물리적주소는 메모리의 같은 공간을 참조한다. 공유메모리는 단일, 중앙 메모리를 의미하는 것은 아니다.

      UMA: uniform memory access, centralized memory MP

      NUMA: non uniform memory access, distributed memory MP

       

  • Challenges of parallel processing
    • 제한된 parallelism, 프로그램의 몇 %정도가 sequential한가?
    • 100개 프로세서에서 80의 speedup을 얻으려고 한다. 원래 프로그램의 몇 %가 sequential한가?

      Speedup_{overall} = \frac{1}{(1-Fraction_{enhanced})+(\frac{Fraction_{parallel}}{Speedup_{parallel}})}

      80 = \frac{1}{(1-Fraction_{parallel})+(\frac{Fraction_{parallel}}{100})}

      80 * (1-Fraction_{parallel})+(\frac{Fraction_{parallel}}{100}) = 1

      79 = 80 * Fraction_{parallel} - 0.8 * Fraction_{parallel}

      Fraction_{parallel} = 79/79.2 = 99.75%

      Amdahl's law로 계산하면, 0.25%만 sequential하다.

      parallel 성능을 위한 새로운 알고리즘 개발

    • remote memory에 접근할 때의 long latency
    • 32CPU MP, 2GHz, 200ns remote memory, 모든 로컬 접근이 메모리 hierarchy를 hit하고 base CPI가 0.5일 때, 0.2%의 인스트럭션이 리모트 접근한다면 성능에 미치는 영향은? (remote access = 200/0.5 = 400 clock cycles)

      CPI = base CPI + remote request rate * remote request cost

      = 0.5 + 0.2% * 400 = 1.3

      즉, 통신이 없는 경우가 2.6배 빠르다.

      shared data를 캐싱(HW)

      로컬 메모리를 더 많이 접근하도록 데이터 레이아웃을 재구성(SW)

       

  • Symmetric shared-memory architectures
    • 중앙메모리와 각 프로세서를 연결하는 버스사용, large cache를 사용함으로서 버스의 BW를 충분히 줄일 수 있다. 프로세서 여러개를 하나의 board로 묶거나, 다중 버스를 사용하거나, interleaved memory를 사용하기도 한다.
    • 각 프로세서의 private data와 프로세서 간의 shared data를 모두 캐싱하는데, 공유데이터의 latency, memory BW, interconnection BW를 모두 줄일 수 있으나, cache coherence문제가 발생할 수 있다.

       

  • Cache coherence problem

    3.jpg

    • 프로세서는 이번트 3 이후에는 다른 값을 보게 된다. write back cache에서 언제 어느 값이 쓰여지고 어떤 캐시가 플러쉬되는가는 happenstance에 의존하므로, 메인 메모리를 접근하는 프로세서는 변경되지 않은 값을 보게 될 수 있고 매우 빈번하다.
    • 아래와 같은 경우, 일관성을 보장할 수 없으나, 서로 다른 프로세서로부터 같은 위치를 접근하도록 요청되었을 때 그 순서를 지키도록 한다. 그러나 같은 위치에대해서만 지켜지므로 coherence가 충분하지 않다.

      4.jpg 5.jpg

    • Intuitive memory model

      어떤 주소 공간을 read할 때, 그 주소에 최종으로 쓰여진 값을 리턴한다. uniprocessor에서는 I/O를 제외하면 쉽다.

      coherence는 read에 의해 리턴되는 값 (같은 장소에 대한 행위), consistency는 언제 쓰여진 값이 read에 의해 리턴 되는가(다른 장소에 대한 행위)

    • 어떤 시스템이 coherence한가?

      preserve program order: X location을 P processor가 read하고 다시 X에 P가 write하기 이전에 다른 프로세서가 X에 write할 수 없도록 한다.

      coherence view of memory: X가 어떤 프로세서에 의해 read 된 후 충분한 시간이 지난 후에는 다른 processor로 부터의 write/read를 허용하고, 이 두 접근 사이에 X에 대한 다른 write가 없어야 한다.

      write serialization: 두 개의 프로세서에 의해 같은 메모리 location에 wrtie가 발생할 경우, 모든 다른 프로세서가 이 순서를 똑같이 보아야 한다. 만약 순서대로 볼 수 없다면, 모든 프로세서가 처음에 쓰여진 값을 보도록 한다.

    • Write Consistency

      모든 프로세서가 어떤 write의 effect를 seen할 때까지 해당 wtire는 완료될 수 없고, 다음 write의 발생을 허용하지 않는다. 프로세서는 그 어떤 메모리 접근과 관련된 어떤 wrtie의 순서도 변경할 수 없다. => 프로세서가 어떤 location A, B에 write한다면 B의 새로운 값을 보는 프로세서는 반드시 A의 새 값을 먼저 보았어야 한다. 이러한 제약은 프로세서가 read의 순서를 재구성하는 것을 허용하지만, 프로세서가 프로그램의 순서대로 write하도록 강제한다. 따라서 성능이 나빠질 수 있다.

    • Basic schemes for enforcing coherence

      몇몇의 캐시에 같은 데이터의 복사보을 둔다.

      SW에서 sharing하는 것을 되도록 피한다. SMP는 coherent cache를 유지할 수 있는 HW protocol을 사용한다.

      migration: 사용되는 로컬 캐시로 데이터를 옮겨 사용

      relpication: 동시에 read되는 데이터를 위해 로컬 캐시에 복사본을 만든다.

    • 2 classes of cache coherence protocols

      directory-based: 특정한 단일 위치에 물리적 메모리 블럭의 상태를 저장하여 공유한다.

      snooping: 데이터의 카피를 갖는 모든 캐시는 메모리 블럭의 상태의 카피도 갖는다. 그러나 centralized status는 유지되지 않는다. 모든 캐시는 버스나 스위치와 같은 broadcast medium을 통해 접근할 수 있다. 모든 캐시 컨트롤러는 요구된 블럭을 medium이 가지고 있는가를 결정하기 위해 이를 모니터하거나 snoop한다.

       

  • Snooping Protocol
    • write invalidate protocol: snooping과 directory scheme에서 다 사용되는 방법으로, 하나의 프로세서가 자신의 write를 완료할 때까지 배타적 접근권을 갖는다. write broadcast의 방법이 있으나, 모든 캐시라인에 모든 write가 브로드캐스트 되어야하기 때문에 다루지 않는다.
    • invalidate protocol의 구현에는 버스의 사용이 핵심, 모든 프로세서는 버스에 접근을 얻거나, invalidate된 주소를 broadcast하고, 주소를 봄으로서 버스를 snoop한다. 프로세서는 버스에 있는 주소가 자신의 캐시에 있는지를 체크하여, 만약 그렇다면 캐시내의 그 데이터를 invalidate한다. 공유된 블럭에 write가 발생하면, writing processor는 invlaidation을 위해 버스 접근을 얻는다. 두 개의 프로세서가 동시에 시도하면, 버스에 의해 중재되어 순서가 결정된다. 즉, 캐시 블럭에 대한 접근의 순서화는 medium의 접근권한의 순서화에 의해 보장된다.
    • 캐시 미스가 발생했을 때, write-through cache에서 모든 쓰여진 데이터가 항상 메모리로 보내지기 때문에 데이터 아이템의 가장 최신 값을 얻기 쉽다. write-through cache는 cache coherence를 구현하는 것을 간단하게 한다. write-back cache는 최신 데이터 값이 메모리가 아닌 캐시에 있는 경우가 많아 최신 값을 찾기 어렵다. 그러나 캐시미스에도 같은 snooping기법을 사용할 수 있다. 모든 프로세서가 버스에 있는 주소를 snooping한다. 어떤 프로세서가 요구된 캐시 블럭의 dirty copy를 찾으면, 이를 read에 대한 응답으로 제공하고 메모리 접근을 중단한다. 다른 프로세서의 캐시로부터 데이터 블럭을 가져오는 것이 공유메모리로부터 가져오는 것보다 복잡도가 높지만, WB 캐시는 낮은 BW를 요구하기 때문에 더 많은 빠른 프로세서를 지원할 수 있고, 많은 MP에서 이를 사용한다.
    • normal cache tags로 프로세서 스누핑 구현, invalidation을 위해 각 블럭당 valid bit 을 사용한다. invalidation이나 다른 이벤트에 의해 발생되는 read miss는 스누핑 능력에 의존하므로 간단하게 구현, write의 경우, 해당 블럭의 카피가 캐시되었는가를 알아야 하는데, 캐시된 카피가 없다면 이 write는 bus에 기록될 필요가 없다. write를 보내지 않는 것은 시간과 BW를 절약한다.
    • 캐시블럭이 공유되는가를 체크하기 위해 각 캐시 블럭에 state bit을 추가한다.valid bit, dirty bit, 공유 블럭에 write할 때 invalidate해야 하는지 아닌지를 결정, 해당 블럭은 exclusive하게 mask되고 프로세서는 그 블럭의 owner가 된다. 나중에 다른 프로세서가 이 블럭을 요구할 때, 다시 shared 상태가 된다.
    • 모든 버스 트랜잭션은 잠재적으로 프로세서 캐시 접근을 방해할 수 있는 cache-address tag를 체크해야 한다. 이러한 방해를 줄이는 한가지 방법은 태그를 복제하는 것이고, 또 다른 방법은 L2 tag를 사용하는 것이다. 모든 L1캐시는 L2캐시에 반드시 표현되어야 한다. (inclusion property) snoop가 L2캐시에서 hit하면, L1캐시가 status를 update하도록 조정하고, 보통 데이터의 stall을 요구하는 데이터를 가져오도록 한다.

       

  • Example protocol
    • snooping protocol 은 finite state controller로 구현되는데, 선택된 캐시 블럭의 상태 변화와 버스가 데이터에 접근하거나 invalidate하는 상태로 표현
    • Write back cache의 Snoopy protocol

      버스의 모든 address를 스누핑한다. 요구된 블럭의 dirty copy를 버스가 가지고 있으면, 해당 블럭을 응답으로 제공하고 메모리 접근을 중단한다.

      메모리는 Shared: 모든 캐시가 최신 데이터인 상태, Exclusive: 정확히 한 캐시만 dirty인 상태, 어떤 캐시에도 없는 상태 중 하나를 갖는다.

      캐시는 share:블럭이 읽기가능한 상태, exclusive: 캐시가 카피를 가지고 있다. 쓰기 가능, dirty, invalid: 블럭이 데이터를 가지고 있지 않는 상태

      읽기 미스는 모든 캐시가 버스를 스누핑하게 한다.

      블럭을 클린하게 하는 쓰기는 미스로 간주된다.

      1(1).JPG 2(1).JPG 3(1).JPG 4(1).JPG

  • Example
    • A1과 A2는 같은 캐시블럭에 맵핑되어 있고 초기 캐시상태는 invalid이다.

      5(1).JPG 6.JPG 7.JPG 8.JPG 9.JPG 10.JPG

  • cache coherence mechanism은 프로세서와 버스 양족으로부터 리퀘스트를 받고 그 리퀘스트의 타입(캐시에서 hit인지 miss인지)에 따라 응답한다. 캐시블러의 상태는 리퀘스트에 명시된다.
  • Limitation in symmetric shared-memory MP and snooping protocol
    • 싱글 메모리가 모든 CPU를 다룬다. 다중 메모리 뱅크가 필요
    • 버스 기반 MP이지만 버스가 coherence traffic과 normal memory traffic을 모두 지원해야 한다. 다중 버스나 interconnection network사용(cross bar or small point-to-point)

     

이 글은 스프링노트에서 작성되었습니다.

저작자 표시 비영리 동일 조건 변경 허락
Creative Commons License
Creative Commons License

이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)

 Vector Computers

  • Vector Supercomputers(Clay-1)
    • scalar unit +  vector extensions :  vector load/store architecture, vector register(SIMD 처리), vector instructions, hardwired control, highly pipelined FUs, interleaved memory system, no data caches(레지스터가 크기때문에 필요없다), no virtual memory(address translation시간을 없애기 위해)
    •  Clay-1의 Architecture(참고)

      1(2).jpg

       

  • Vector programming
  • Vector length register에 작동 범위 할당 가능, [vector length register max -1], 메모리의 r1(base)부터 시작하여, r2(stride)의 간격으로 LD, SD한다.

2.jpg


  • Vector code example
    • C code

      for (i = 0; i < 64; i++)

      C[i] = A[i] + B[i];   //C[1] = A[i] + C[i]; 일 경우 벡터 op 불가

       

    • # Scalar code

      LI R4, 64

      Loop:

      L.D F0, 0 (R1)

      L.D F2, 0 (R2)

      ADD.D F4, F2, F0

      S.D F4, 0 (R3)

      DADDIU R1, 8

      DADDUI R2, 8

      DADDUI R3, 8

      DSUBUI R4, 1

      BNEZ R4, Loop

       

    • # Vector code

      LI VLR, 64

      LV V1, R1

      LV V2, R2

      ADDV.D V3, V1, V2

      SV V3, R3

       

  • Vector Instruction Set Advantage
    • compact: (당연히) 한 개의 짧은 인스트럭션으로 여러 개의 오퍼레이션을 표현할 수 있다.

      expressive: N개의 오퍼레이션 독립적이며, 같은 FU를 사용하고, disjoint register에 접근하며, 이전 인스트럭션과 같은 패턴으로 레지스터에 접근하고, 계속적인 메모리 블럭에 접근하거나(unit-stride load/store), 정해진 연속 패턴에 의한 메모리 접근을 수행(strided load/store) - > 한다는 것을 하드웨어에 표현한다.

      scalable: 더욱 parallel한 pipeline이나 lane에서 같은 오브젝트 코드를 수행할 수 있다.

       

  • Vector arithmetic execution
    • 각 element op를 수행하기 위해 deep pipeline (fast clock)사용
    • vector의 각 element는 서로 독립적이기 때문에 hazard가 발생하지 않고, 때문에 deep pipeline을 관리하기 편리하다.
    • 일반적으로 load-store unit을 start-up하는 페널티는  arithmetic FU보다 훨씬 크다.

       

  • Vector memory system
    • Clay-1에서 16 banks, 4 cycle bank busy time, 12 cycle latency(cycle busy time은 한 bank에 접근했다가 같은 bank에 다시 접근할대까지의 cycle 수를 의미)

      3.jpg

    • 일반적으로 load-store unit을 start-up하는 페널티는  arithmetic FU보다 훨씬 크다. 따라서 memory 시스템은 클럭당 1 word를 저장하거나 fetch 할 수 있어야 한다. 메모리 시스템은 여러개의 독립적인 뱅크로 구성되어 메모리 접근을 분산시켜 이루어진다.

      많은 벡터 컴퓨터가 클럭당 다중 로드/스토어를 지원하고, 종종 CUP cycle time 보다 memory bank cycle time이 몇 배 클 수 있다. 동시에 다중 접근을 지원하기 위해 메모리 시스템은 다중 뱅크를 갖으며 뱅크에 접근하는 주소를 독립적으로 관리할 수 있어야 한다.

      많은 벡터 컴퓨터가 워드를 로드/스토어할 때 sequential하지 않게 할 수 있다. 이와 같은 경우, interleaving보다 독립적인 banking addressing이 더 요구된다.

      벡터 컴퓨터는 멀티 프로세서가 같은 메모리를 공유하는 것을 허용한다. 그리고 각 프로세서는 자신만의 독립된 주소 스트림을 생성한다.

      • CPU clock 2.167 ns, 32 processor가  각각 4 loads, 2 stores를 클럭당 생성하고, 메모리 시스템의 clock time니 15ns 라면, 요구되는 뱅크의 갯수는?

        32 * 6 (프로세서 * 6번 로드/스토어) = 192

        메모리 뱅크는 15/2.167 = 6.92 CPU clock cycle 동안 busy(대략 7)

        192 * 7 = 1344 메모리 뱅크 필요

         

  • Vector Instruction Excution
    • 1 pipeline과 4 pipelined FU를 사용할 때

      4.jpg

       

  • Vector Unit Structure
    • FU에 맞게 레지스터를 분배하고, 연속된 데이터가 서로 다른 레지스터에 저장될 수 있도록 한다.
    • FU가 충분하다면 각각 독립된 레지스터 셋을 갖기 때문에 intruction 수행시 동시에 여러 레지스터를 read 할 수 있다.

      5.jpg


  • Vector Memory-memory vs. Vector register machine
    • VMM instruction은 모든 벡터 피연산자를 메모리에 유지한다. 즉, 메모리에 직접 연산하는데 비해, 벡터 레지스커 머신은 벡터 레지스터로 로드하는 연산을 한다.

      6.jpg

    • VMM architecture가 더 큰 메모리 bandwidth를 요구하는이유?

      모든 피연산자가 메모리에 read in/out

    • VMMA는 다중 벡터 연산의 실행이 오버랩되기 어렵다. 이유?

      메모리 주소의 의존성(dependency)를 체크해야 하기 때문에

    • VMMA는 strat-up latency가 더 크다.
    • 메이져 벡터 머신은 모두 벡터 레지스터 머신이다.

       

  • Automatic Code Vectorization
    • 오퍼레이션의 순서를 재배치 하기 위해 엄청난 컴파일 타임이 걸린다. --> extensive loop dependence analysis

  • Vector Stripmining
    • 벡터 레지스터의 길이가 제한되어 있기 때문에, 루프를 쪼개어 벡터 레지스터에 맞춘다.
    • # C code

      for (i = 0; i < N; i++)

      C[i] = A[i] + B[i];

    • # Vector stripmining

      ANDI R1, N, 63 // N mod 64

      MTC1 VLR, R1 // Do remainder // mod 연산 수행한 나머지, copy 32bits from FP register to integer register

      loop:

      LV V1, RA

      DSLL R2, R1, 3 // Multiply by 8 // Shift left logically

      DADDU RA, RA, R2 // Bump pointer

      LV V2, RB

      DADDU RB, RB, R2

      ADDV.D V3, V1, V2

      SV V3, RC

      DADDU RC, RC, R2

      DSUBU N, N, R1 // Subtract elements

      LI R1, 64

      MTC1 VLR, R1 // Reset full length

      BGTZ N, loop


  • Vector instruction parallelism
    • 다중 벡터 연산의 오버랩 가능
    • 8개의 lane이 있고, 한 벡터 레지스터 당 32개의 엘리먼트를 갖는 머신이라고 하면, 사이클당 1개 인스트럭션이 이슈되고, 24개의 오퍼레이션이 완료된다.

       

  • Vector chaining
    • 벡터 레지스터에 로드나 이전 연산이 완료되지 않아도, 일부 데이터만 가져다가 연산에 사용

      8.jpg

    • 체이닝을 사용하지 않는다면 연관있는 이전 인스트럭션의 마지막 엘리먼트가 종료될때까지 다음 인스트럭션을 수행할 수 없다. 체이닝을 할 경우, 이전 인스트럭션의 결과가 나오자 마자 연관된 다음 인스트럭션 수행 가능

       

  • Vector startup
    • 다중 lane을 사용하여 성능을 증가시킨다고 해도, startup latency를 줄일 수 없다. 그러나, 이전 벡터 인스트럭션의 완료와 다른 벡터 인스트럭션의 시작이 오버랩되도록 하여 startup overhead를 줄일 수 있는데, 가장 심플한 방법은 두 개의 벡터 인스트럭션이 서로 다른 벡터 레지스터를 접근하도록 하는 것이다.
    • 일부 벡터 머신에서는 첫번째 벡터 인스트럭션의 마지막 엘리먼트와 다음 인스트럭션의 첫번째 엘리먼트 사이에 dead time을 두어 제어 로직을 간단히 한다.
    • 따라서, vector startup penalty는 FU latency, 즉 파이프라인을 지나는 시간 + dead time(recovery time), 즉 파이프라인에서 다른 벡터 인스트럭션이 시작되기 전까지의 시간이다.

      1(3).JPG

       

  • Vector Scatter/Gather
    • Gather: indirect ADD mode를 이용하여 여기저기서 load, load 연산은 같은 address에 두 번 접근해도 관계없음

      for ( i = 0; i < N; i++)

      A[i] = B[i] + C[D[i]];

      LV VD, RC // 벡터 D로부터 인덱스를 로드

           LVI VC, RC, VD // 간접주소로 벡터 C 로드

           LV VB, RB

           ADDV.D VA, VB, VC

           SV VA, RA

    • Scatter: store 연산은 두 번 접근하면 안되기때문에, store를 순차적으로 할 수 없는 시스템에서는 indirect add를 이용한  stroe는 불가

      for ( i = 0; i < N; i++)

              A[B[i]] ++;

      LV VB, RB // indices

           LVI VA, RA, VB

           ADDV VA, VA, 1 // increment

           SVI VA, RA, VB // scatter incremented value

       

  • Vector conditional execution
    • 조건에 따른 실행을 위해 vector mask를 추가한다. 각 엘리먼트 당 1 bit, predicate register의 벡터 버전, 마스크 비트가 클리어 한 엘리먼트에서 벡터 인스트럭션은 NOP가 된다.

      for ( i = 0; i < N; i++)

              if (A[i] > 0) then

                  A[i]  = B[i];

      CVM // turn on all element

           LV VA, RA // load entire A vector

           SGTVS.D VA F0 // set bits in mask register where A > 0

           LV VA, RB // load B vector into A under mask

           SV VA, RA // store A back to memory under mask

    • Masked vector instruction: 모든 오퍼레이션을 실행하고 bit이 set된 오퍼레이션을 저장하지 않는 구현 vs. bit에 따라 아예 pipeline에 들어가지 않도록 하는 구현

      2(1).JPG

    • Compress/Expand operations

      3(1).JPG

       

  • Vector Reduction:
    • Problem: Loop-carried dependence on reduction variables

      sum = 0;
          for (i=0; i<N; i++)
          sum += A[i]; # Loop-carried dependence on sum

    • Solution: Re-associate operations if possible, use binary tree to perform reduction

      # Rearrange as:
           sum[0:VL-1] = 0 # Vector of VL partial sums
           for(i=0; i<N; i+=VL) # Stripmine VL-sized chunks
           sum[0:VL-1] += A[i:i+VL-1]; # Vector sum
           # Now have VL partial sums in one vector register
           do {
              VL = VL/2; # Halve vector length
              sum[0:VL-1] += sum[VL:2*VL-1] # Halve no. of partials
                } while (VL>1)


  • Common vector metrics
    • R_\infty: MFLOPS rate on an infinite-length vector

      벡터 길이가 무한하다면 빛의 속도, 실제로는 무한한 벡터 길이는 없고, startup penalty가 존재한다.

    • N_\frac{1}{2}: R_\infty의 절반에 가까워지기위해 필요한 벡터의 길이, startup의 영향을 측정
    • N_V: 스칼라 모드보다 벡터 모드가 빨라지기 위한 벡터 길이,startup, 벡터에 대해 상대적인 스칼라의 속도, 스칼라 유닛과 벡터 유닛의 커넥션의 질을 측정

       

  • Vector execution time
    • Time = f(vector length, data dependency, structural hazards)
    • initiation rate: FU가 소비하는 벡터 엘리먼트의 비율(=lane의 갯수)
    • convoy: 같은 클럭에 시작되는 벡터 인스트럭션의 집합(no data hazard, struc. hazard)
    • chime: 벡터 오퍼레이션의 대략적인 time
    • m convoys take m chimes; 벡터 길이가 n이면, 대략 m * n 클럭 사이클이 걸린다.
    • 4 convoys, 1 lane, VL =64 ==> 4 * 64 = 256 clocks(4 clocks per result)

       

  • Memory operation
    • 세가지 어드레싱 타입

      Unit stride: 인접된 블럭, 가장 빠르다.

      Non-unit stride: 모든 가능한 stride에 대해 메모리 시스템을 최적화하기는 어렵다. full bandwidth에서 서로 다른 stride를 지원하기 쉽도록 하기 위해 prime수의 메모리 뱅크 사용

      indexed(gather-scatter): register indirect와 동등한 벡터, sparse array에 적합, 벡터화하는 프로그램의 수를 증가

    • interleaved memory layout, unit stride에는 좋다. 서로 다른 DRAM의 인접 엘리먼트,

      startup time은 single read의 latency와 같다. non-stride에는 bank의 수가 prime이라면 좋다.

      4(1).JPG

    • How to get full bandwidth for Unit Stride?

      메모리 시스템은 (#lanes * world)/clock을 유지해야 한다. 메모리 뱅크의 수 >  stall을 피하기 위한 메모리 레이턴시

      m banks => m word per memory latency l clocks

      m<l 이면 메모리 파이프라인에서의 갭은

          clock: 0 ... l   l+1   l+2 ... l+m-1   l+m ... 2l

          word: -- .. 0    1    2  ... m-1       --  ... m

      클럭 당 1 워드보다 더 큰 throughput이 요구될 경우

      뱅크를 늘린다, 동시에 여러 리퀘스트를 시작

      wider DRAM사용, 큰 데이터 타입이나 unit stride일 때만 좋음

      많은 수의 뱅크는 full bandwidth로 더 많은 stride를 지원하는 데 좋다.

       

  • Vextor vs. Scalar or Superscalar
    • 벡터는 비용이 비싸지 않다.

      싸이클 당 N개의 op를 수행한다고 하면, 스칼라 O(N^2) circuitry, 벡터 O(N+\epsilon*N^2) circuitry, 벡터는 사이클 당 실행하는 op의 갯수가 많고, transistor의 수가 비교적 적게 요구되고, FP가 없다.

    • 벡터는 적은 파워를 사용한다.

      싱글 스칼라의 경우, 매번 op 마다 fetch, decode, dispatch를 수행한다. 벡터는 벡터 단위로 수행

      임의적 레지스터 접근 vs. 구조적 레지스터 접근

      루프 언롤링이나 소프트웨어 파이프라이닝등 높은 퍼포먼스를 위해 인스트럭션 캐시의 비중이 높다. vs. 성능을 위해서는 적은 코드 사용

      모든 데이터가 캐시를 거치기 때문에 temporal locality가 없는 경우 파워 낭비 vs. bypass cache

       로드/스토어 연산시 TLB lookup vs. 로드/스토어 그룹 연산시 TLB lookup

      모든 캐시 라인에서 off-chip access vs. chip boundary에서 필요한 데이터만 이동

    • Superscalar energy efficiency even worse

      issue width에 따라 control logic이 제곱으로 증가 vs. linear하게 증가

      컨트롤 로직이 available한 parallelism과 관계없이 소비된다. vs. 벡터 유닛은 사용되지 않을때는 스위치 오프

      parallelism을 증가시키는 speculation은 에너지를 낭비한다. vs. speculation없이 parallelism을 증가시킨다. 필요할 때만 SW speculation control(컨디션에 따라 벡터 마스크나 compress/expand를 사용할 때)

       

  • Vector Summary
    • ILP를 높일 수 있는 대안적 모델
    • 코드가 벡터화되어 있으면, 하드웨어가 간단해지고, 에너지 사용이 효율적이며, out-of-oeder machine보다 더욱 real time model이 된다.
    • lane의 갯수, FU의 갯수, VR의 갯수, VR의 길이, 예외나 조건문의 처리 등이 디자인 이슈이다.
    • 가장 기본적인 이슈는 메모리 bandwidth(with virtual address translation and caching)
    • 멀티미디어의 발달은 벡터 머신의 필요성이 다시 대두되도록 할 것인가?

이 글은 스프링노트에서 작성되었습니다.

저작자 표시 비영리 동일 조건 변경 허락
Creative Commons License
Creative Commons License
수업을 좀 빠져서...중간중간에 스킵된 내용을 때우느라고 조금 힘들었다능...
사실 출력 부분이 두 번씩 출력되는 것이...출력문의 위치를 잘못 넣은 것 같긴 하지만
대충 얼추 비슷하게 나오는 것 같아서 그냥 두었다는...
(사실 치명적인 실수가 숨어 있을지 모르지만, 귀찮으니 그냥 넘어간다...지금보니 변수의 철자도 맞지 않는 것이..쿨럭...)

지난 번의 Auction에서 조금 변경된 형태로, 수요자와 공급자가 함께 입찰을 하는 방식이다.
공급자의 가격이 수요자의 요구 가격보다 낮아질 때 낙찰된다.

  • Double Auction Model은 기존의 Auction Model이 단 방향성인데 비해서 Supplier와 Customer가 전부 입찰에 참여 할 수 있다.

  • Double Auction 모델은 3부분으로 구성되는데 Supplier, Auctioneer, Customer로 구성된다.

  • 입찰이 시작되면 Supplier와 Customer가 최초 입찰 가격을 제시 한다.

  • 추후 입찰에서 Supplier는 기존 입찰에서 자신의 가격 탄력성 (Price Elasticity) 하에서 입찰 가격을 하락 시켜 입찰하고 Customer는 자신의 가격 탄력성 (Price Elasticity) 하에서 입찰 가격을 상승 시켜 입찰을 진행한다.

  • 가격 탄력성의 수치는 입찰 횟수가 많아질수록 상세 가격 조정을 위해 낮아진다.

  • SBP(Supplier’s Bidding Price)와 CBP(Customer’s Bidding Price)는 다음과 같다.
    • SBP = Previous Bidding Price of Supplier – Rand(Price Elasticity of Supplier)
    • CBP = Previous Bidding Price of Customer + Rand(Price Elasticity of Customer)

  • Supplier와 Customer의 입찰 가격 곡선


PROCESS
  1. Auctioneer 가 Supplier와 Customer에게 경매가 시작됐음을 알린다.
  2. Supplier와 Customer는 최초 입찰 가격을 Auctioneer에게 보낸다.
  3. Auctioneer는 양측의 입찰 가격을 비교하여 가격 균형이 이루어 졌는지 확인해 본 후 가격 균형이 이루어 진 경우 입찰을 종료 하고 아니면 추가 입찰을 통보 한다.
  4. Supplier와 Customer는 입찰 가격을 재 조정하여 다시 입찰한다.
    1. SBP = Previous Bidding Price of Supplier – Rand(Price Elasticity of Supplier)
    2. CBP = Previous Bidding Price of Customer + Rand(Price Elasticity of Customer)
  5. 3번을 진행한다.
  6. 입찰이 종료 되면 종료 메시지와 함께 양측에 입찰 가격을 보낸다.



PROCEDURE and DESIGN

DEVS로 구성 시 만들어지는 1개의 Digraph 모델과 3종류의 Component(Atomic Model)와 4종류의 Message로 구성된다.
  • Double Auction: gpt.java를 수정하여 만든다. (Digraph Model)

  • Supplier, Auctioneer, Customer: proc.java를 수정하여 만든다.

  • 4 Messages: job.java를 수정하여 만든다.
    • Start Message: Auctioneer -> Supplier and Customer로 전달된다. 경매 시작을 알리는 메시지다.
    • Bidding Message: Customer and Supplier -> Auctioneer로 전달되는 메시지로 Customer와 Supplier의 입찰 가격을 포함하고 있다. (# of stage를 포함)
    • Result Message: Auctioneer -> Customer and Supplier로 전달되는 메시지로 양측이 입찰이 끝나면 입찰 가격을 비교 하여 결과를 알려준다. 추가 입찰이 필요한 경우 추가 입찰에 관한 내용도 포함하고 있다.
    • Terminate Message: Auctioneer -> Customer and Supplier로 전달되는 메시지로 경매가 끝났음을 알리는 메시지로 최종 낙찰 가격 (Price Equilibrium)을 가지고 있다.

  • Time Out: Stage가 7회 이상되면 가격 절충에 실패한 것으로 간주하여 경매를 종료한다. /* Time out은 구현하지 않았음, ^^;; 좀처럼 7회 안에 낙찰결과를 얻을 수가 없었기때문에..그냥 낙찰될 때까지 두었다. */



EXPERIMENTS

  • Supplier에게는 무한의 Product가 있다고 가정 (10000 ~ 20000사이의 가격에서 랜덤하게 설정)

  • Product에 대한 Supplier의 Initial Price (First Bidding Price) = 원가 × 1.25

  • Customer의 First Bidding Price = FBP of Supplier × 0.85

  • 가격 탄력성 PE = (int)(PE×((Stage_Number-1)×0.9)), 단 stage 1의 PE = PE×1이다.
    /* PE = (int)(PE×((Stage_Number-1)×0.99)) 로 변경
    0.9일 때, 낙찰되기 전에 0이 되어 한 건의 낙찰도 이루어지지 않았기 때문에... */

  • Result Price = (int)(Last Bidding Price of Supplier + Last Bidding Price of Customer)/2

  • 두 개의 Double Auction 모델을 비교
    • Model 1:
      Supplier 와 Customer의 PE = 100 이하의 값 중 랜덤하게 선택
    • Model 2:
      Supplier 와 Customer의 PE = 150 이하의 값 중 랜덤하게 선택
    • Model 3:
    • Supplier의 PE = 100 이하 의 값 중 랜덤하게 선택
      Customer의 PE = 150 이하 의 값 중 랜덤하게 선택
    • Model 4:
      Supplier의 PE = 150 이하 의 값 중 랜덤하게 선택
      Customer의 PE = 100 이하 의 값 중 랜덤하게 선택



PERFORMANCE MEASURE

  1. 누적 거래 성사 횟수 (SPE = Supplier’s Price Elasticity, CPE = Customer’s Price Elasticity)

  2. 평균 입찰 횟수 (SPE = Supplier’s Price Elasticity, CPE = Customer’s Price Elasticity)
    Supplier의 입찰 횟수 합 / 거래성사 횟수

  3. Supplier의 평균 이익과 Customer의 평균 지출 (1000, 2000, 3000, 4000, 5000 Devs time)
    Supplier의 평균 이익 = Average (판매가격 – 원가)
    Customer의 평균 지출 = Average (판매 가격)



// DoubleAuction.java
// 2009. 06. 01
// Modified by Aettie Ji

package SimpArc;

import java.awt.*;
import simView.*;
import genDevs.modeling.*;
import genDevs.simulation.*;
import GenCol.*;

public class DoubleAuction
    extends ViewableDigraph {
  double cPTime = 50; // Customer processing time
  double sPTime = 50; // Supplier processing time
  double aPTime = 50; // Auctioneer processing time
  double observTime = 10000;

  int SPE = 150; // Price elasticity of supplier
  int CPE = 100; // Price elasticity of customer
  // product initial price
  int[] iniPrice = {
      15400, 12800, 14200, 11400, 18200, 16300, 12900, 10500, 11000, 17900};

  public DoubleAuction() {
    super("DoubleAuction");
    // Customer processing time, initial Price, Customer 가격 탄력성
    ViewableAtomic c =
        new DA_Customer("Customer", cPTime, iniPrice, CPE);
    // Supplier processing time, initial Price, Customer 가격 탄력성
    ViewableAtomic s =
        new DA_Supplier("Supplier", sPTime, iniPrice, SPE);
    // Auctioneer processing time, initial Price, Observation time
    ViewableAtomic a =
        new DA_Auctioneer("Auctioneer", aPTime, iniPrice,
                                         observTime);

    add(c);
    add(s);
    add(a);

    addCoupling(a, "start_out", c, "start_in"); //경매시작
    addCoupling(a, "start_out", s, "start_in");
    addCoupling(a, "result_out", c, "result_in"); //경매결과
    addCoupling(a, "result_out", s, "result_in");

    addCoupling(a, "terminate_out", c, "terminate_in"); //경매종료
    addCoupling(a, "terminate_out", s, "terminate_in");

    addCoupling(s, "bidding_out", a, "sBidding_in"); //입찰
    addCoupling(c, "bidding_out", a, "cBidding_in");

    addCoupling(s, "ACK_out", a, "ACK_in"); //Acknowledgement
    addCoupling(c, "ACK_out", a, "ACK_in");
  }

  public void layoutForSimView() {
    preferredSize = new Dimension(816, 409);
    ( (ViewableComponent) withName("Auctioneer")).setPreferredLocation(new
        Point(414, 121));
    ( (ViewableComponent) withName("Customer")).setPreferredLocation(new Point(
        44, 279));
    ( (ViewableComponent) withName("Supplier")).setPreferredLocation(new Point(
        17, 59));
  }
}


// DA_Auctioneer.java
// 2009. 06. 01
// Modified by Aettie Ji

package SimpArc;

import genDevs.modeling.*;
import genDevs.simulation.*;
import GenCol.*;
import simView.*;

public class DA_Auctioneer
    extends ViewableAtomic {
  protected entity job;
  protected double processing_time; // Auctioneer의 processing time

  BiddingMessage bm;
  boolean sIn, cIn; // 입찰 여부 체크
  String msgName;
  String portName;
  double clock; //observation time check
  int proCount; // product count
  int cBiddingPrice;
  int sBiddingPrice;
  int terminatePrice; // 낙찰 가격
  double observTime;
  int[] iniPrice; // product initial price

  // 통계를 위한 변수
  int priceEqualibrium; // 거래성사횟수
  double avgBidding; // 평균 입찰 횟수 = Supplier의 입찰 횟수/거래성사횟수
  int sbiddingCnt = 0; // Supplier의 입찰 횟수
  int supplierProfit = 0; // Supplier의 이윤 = 낙찰가격 - 상품원가
  int customerCost = 0; // Customer의 지출 = 낙찰가격
  double avgSProfit = 0; // supplierProfit의 평균
  double avgCCost = 0; // customerCost의 평균

  public DA_Auctioneer(String name, double Processing_time, int[] initial_price,
                       double observation_time) {
    super(name);

    processing_time = Processing_time;
    observTime = observation_time;
    this.iniPrice = initial_price;
    addInport("cBidding_in");
    addInport("sBidding_in");
    addInport("ACK_in");
    addOutport("result_out");
    addOutport("terminate_out");
    addOutport("start_out");
  }

  public void initialize() {
    //phase = "passive";
    holdIn("active", processing_time);
    job = new entity("job");
    msgName = "Start Message";
    portName = "start_out";
    clock = 0;
    proCount = 0;
    cBiddingPrice = 0;
    sBiddingPrice = 0;
    priceEqualibrium = 0;
    terminatePrice = 0;
    avgBidding = 0;
    sIn = false;
    cIn = false;
    //sigma = INFINITY;
    bm = new BiddingMessage("");

    super.initialize();
  }

  public void deltext(double e, message x) {
    clock += e;
    Continue(e);
    if (clock > 10000) { // DEVS time이 10000이면 프로그램 종료
      System.out.println(
          "===============OBSERVATION TIME is OVER!!!=================");
      System.exit(0);
    }
    if (phaseIs("passive")) {
      for (int i = 0; i < x.getLength(); i++) {
        if (messageOnPort(x, "cBidding_in", i)) {
          job = x.getValOnPort("cBidding_in", i);
          bm = (BiddingMessage) job;
          cBiddingPrice = bm.nBiddingPrice;
          cIn = true;
//        System.out.println("Customer Bidding Message in***" + bm.nBiddingPrice);
        }
        if (messageOnPort(x, "sBidding_in", i)) {
          job = x.getValOnPort("sBidding_in", i);
          bm = (BiddingMessage) job;
          sBiddingPrice = bm.nBiddingPrice;
          sIn = true;
          sbiddingCnt++;
//        System.out.println("Supplier Bidding Message in***" + bm.nBiddingPrice);
          holdIn("busy", processing_time);
        }
        if (messageOnPort(x, "ACK_in", i)) {
          job = x.getValOnPort("ACK_in", i);
          msgName = "Start Message";
          portName = "start_out";
//         System.out.println("ACK Message in****************" );
          holdIn("busy", processing_time);
        }
        if (cIn == true && sIn == true) {
//         System.out.println("Both Bidding Message in****************");
          msgName = "Result Message";
          portName = "result_out";
          if (sBiddingPrice <= cBiddingPrice) {//Supplier의 가격이 낮거나 같으면 경매 성사
//           System.out.println("sBiddingPrice <= cBiddingPrice****************");
            if ( (sBiddingPrice != 0) && (cBiddingPrice != 0)) {
              terminatePrice = (int) (Math.round( (double) ( (sBiddingPrice +
                  cBiddingPrice) / 2)));
              msgName = "Terminate Message";
              portName = "terminate_out";
              priceEqualibrium++; // 경매 성사 횟수 증가
              // Supplier의 이윤 = 낙찰가격 - 상품원가
              supplierProfit += (terminatePrice - iniPrice[proCount]);
              // Customer의 지출 = 낙찰가격
              customerCost += terminatePrice;
              System.out.println(
                  "#################### Auctioneer MSG ####################");
              System.out.println("InitPrice: " + iniPrice[proCount]);
              System.out.println("DEVS clock: " + clock);
              System.out.println("Number of Price equalibrium: " +
                                 priceEqualibrium);
              System.out.println("Supplier's Bidding Price: " + sBiddingPrice);
              System.out.println("Customer's Bidding Price: " + cBiddingPrice);
              System.out.println("Last Price: " + terminatePrice);
              System.out.println(
                  "################ End of Auctioneer MSG #################");
              sBiddingPrice = 0;
              cBiddingPrice = 0;
              terminatePrice = 0;
              proCount++;
              sIn = false;
              cIn = false;
              if (proCount >= iniPrice.length) {
                proCount = 0;
              }
            }
          }
        }
        if (clock % 1000 == 0) { // DEVS time 1000마다 각 통계치 출력
          if (priceEqualibrium != 0) {
            avgBidding = (double) sbiddingCnt / (double) priceEqualibrium;
            avgSProfit = (double) supplierProfit / (double) priceEqualibrium;
            avgCCost = (double) customerCost / (double) priceEqualibrium;
            System.out.println(
                "============================================================");
            System.out.println("DEVS clock :" + clock);
            System.out.println("Supplier Bidding Count :" + sbiddingCnt);
            System.out.println("Number of Price equibrium: " + priceEqualibrium);
            System.out.println("Average Bidding: " + avgBidding);
            System.out.println("Average Supplier Profit :" + avgSProfit);
            System.out.println("Average Customer Cost :" + avgCCost);
            System.out.println(
                "============================================================");
          }
        }

      }
    }
  }

  public void deltint() {
    clock = clock + sigma;
    passivate();
  }

  public void deltcon(double e, message x) {
    deltint();
    deltext(0, x);
  }

  public message out() {
    message m = new message();
    if (msgName == "Start Message") {
      content con = makeContent(portName, new StartMessage("Start Message"));
      m.add(con);
//      System.out.println(
//                "=====Start Message out from: Auctioneer to: S and C=====");
    }
    else if (msgName == "Result Message") {
      content con = makeContent(portName,
                                new ResultMessage("Result Message",
                                                  cBiddingPrice,
                                                  sBiddingPrice));
      m.add(con);
//     System.out.println(
//                "=====Result Message out from: Auctioneer to: S and C====="
//                 +"C: "+cBiddingPrice+"S: "+sBiddingPrice);
    }
    else if (msgName == "Terminate Message") {
      content con = makeContent(portName,
                                new TerminateMessage("Terminate Message",
          terminatePrice));
      m.add(con);
//    System.out.println(
//              "=====Terminate Message out from: Auctioneer to: S and C====="
//               +terminatePrice);
    }
    return m;
  }

  public void showState() {
    super.showState();
    System.out.println("job: " + job.getName());
  }

  public String getTooltipText() {
    return
        super.getTooltipText()
        + "\n" + "job: " + job.getName();
  }
}


// DA_Supplier.java
// 2009. 06. 01
// Modified by Aettie Ji

package SimpArc;

import genDevs.modeling.*;
import genDevs.simulation.*;
import GenCol.*;
import simView.*;

public class DA_Supplier
    extends ViewableAtomic {

  protected entity job;
  double sPTime; // processing time
  int iniSPE; // initial price elasticity
  int nFinaliniSPE;

  int[] aIniPrice; // 초기 가격 저장
  int iniPrice, proCnt, sBiddingPrice, resultPrice; // Bidding price+price elasticity
  int nStage = 0;
  String msgName, portName; // message name, port name

  StartMessage sm; // Auctioneer로부터 받은 initial price
  ResultMessage rm; // 이전 입찰정보
  TerminateMessage tm; // 낙찰 정보

  public DA_Supplier(String name, double SPT, int[] AIP, int SPE) {
    super(name);
    this.sPTime = SPT;
    this.aIniPrice = AIP;
    this.iniSPE = SPE;
    nFinaliniSPE = iniSPE;

    addInport("start_in");
    addInport("result_in");
    addInport("terminate_in");
    addOutport("ACK_out");
    addOutport("bidding_out");
  }

  public void initialize() {
    phase = "passive";
    sigma = INFINITY;
    job = new entity("job");
    iniPrice = 0;
    proCnt = 0;
    sBiddingPrice = 0;
    resultPrice = 0;

    sm = new StartMessage("");
    rm = new ResultMessage("");
    tm = new TerminateMessage("");

    super.initialize();
  }

  public void deltext(double e, message x) {
    Continue(e);

    if (phaseIs("passive")) {
      for (int i = 0; i < x.getLength(); i++) {
        if (messageOnPort(x, "start_in", i)) {
          job = x.getValOnPort("start_in", i);
          sm = (StartMessage) job;
          iniPrice = aIniPrice[proCnt];
          sBiddingPrice = (int) (Math.round(iniPrice * 1.25)); //초기입찰가격
          msgName = "Bidding Message";
          portName = "bidding_out";
        }
        else if (messageOnPort(x, "result_in", i)) {
          job = x.getValOnPort("result_in", i);
          rm = (ResultMessage) job;
          // System.out.println(
          //    "========Result Message in from: Auctioneer to:S========" +
          //     rm.sBidPrice);
          resultPrice = rm.sBidPrice; //result message 변수 체크
          if (nStage == 1) { //customer에도 같은 작업
            iniSPE = iniSPE;
          }
          else {
            iniSPE = (int) ( (double) iniSPE * (double) 0.99);
            // 원래는 * 0.9지만 몇 차례 입찰 후 iniCPE가 0이 되어 입찰이 진행되지 않기 때문에 변경
          }
          sBiddingPrice = resultPrice - ( (int) (Math.random() * iniSPE)); //새로운 입찰가격
          //  System.out.println(
          //     "SSresultPrice: " + sBiddingPrice + " =  SSresultPrice :" +
          //     resultPrice + " ((int)(Math.random()*iniSPE)): " +
          //     ( (int) (Math.random() * iniSPE)));
          nStage++; //customer에도 같은 작업
          msgName = "Bidding Message"; // 새로운 입찰 가격을 보냄
          portName = "bidding_out";
        }
        else if (messageOnPort(x, "terminate_in", i)) {
          job = x.getValOnPort("terminate_in", i);
          tm = (TerminateMessage) job;
          //   System.out.println("TerminateMessage  out***************");
          iniSPE = nFinaliniSPE; //customer에도 같은 작업
          sBiddingPrice = 0;
          proCnt++; //한 개 상품에 대한 입찰 종료, 다음상품 경매
          //  System.out.println("한 개 상품에 대한 입찰 종료, 다음상품 경매********");
          if (proCnt >= aIniPrice.length) {
            proCnt = 0;
          }
          msgName = "ACK Message";
          portName = "ACK_out";
        }
        holdIn("active", sPTime);
      }
    }
  }

  public void deltint() {
    passivate();
    job = new entity("none");
  }

  public void deltcon(double e, message x) {
    deltint();
    deltext(0, x);
  }

  public message out() {
    message m = new message();
    if (msgName == "Bidding Message") {
      content con = makeContent(portName,
                                new BiddingMessage(msgName, sBiddingPrice));
      m.add(con);
      // System.out.println("Bidding Message out*********" + sBiddingPrice);
    }
    else if (msgName == "ACK Message") {
      content con = makeContent(portName, new BiddingMessage("ACK Message"));
      m.add(con);
      // System.out.println("Supplier ACK Message  out**********");
    }
    return m;
  }

  public void showState() {
    super.showState();
    System.out.println("job: " + job.getName());
  }

  public String getTooltipText() {
    return
        super.getTooltipText()
        + "\n" + "job: " + job.getName();
  }
}


// DA_Customer.java
// 2009. 06. 01
// Modified by Aettie Ji

package SimpArc;

import genDevs.modeling.*;
import genDevs.simulation.*;
import GenCol.*;
import simView.*;

public class DA_Customer
    extends ViewableAtomic {

  protected entity job;
  double cPTime; // processing time
  int iniCPE; // initial price elasticity
  int nFinaliniCPE;

  int[] aIniPrice; //초기 가격 저장
  int iniPrice, proCnt, cBiddingPrice, resultPrice; //Bidding price + price elasticity
  int nStage = 0;
  String msgName, portName; //message name, port name

  StartMessage sm; //Auctioneer로부터 받은 initial price
  ResultMessage rm; //이전 입찰정보
  TerminateMessage tm; // 낙찰 정보

  public DA_Customer(String name, double CPT, int[] AIP, int CPE) {
    super(name);
    this.cPTime = CPT;
    this.aIniPrice = AIP;
    this.iniCPE = CPE;
    nFinaliniCPE = iniCPE;

    addInport("start_in");
    addInport("result_in");
    addInport("terminate_in");
    addOutport("ACK_out");
    addOutport("bidding_out");
  }

  public void initialize() {
    phase = "passive";
    sigma = INFINITY;
    job = new entity("job");
    iniPrice = 0;
    proCnt = 0;
    cBiddingPrice = 0;
    resultPrice = 0;

    sm = new StartMessage("");
    rm = new ResultMessage("");
    tm = new TerminateMessage("");

    super.initialize();
  }

  public void deltext(double e, message x) {
    Continue(e);

    if (phaseIs("passive")) {
      for (int i = 0; i < x.getLength(); i++) {
        if (messageOnPort(x, "start_in", i)) {
          job = x.getValOnPort("start_in", i);
//          System.out.println(
//             "==========Start Message in from: Auctioneer to: C=========");
          sm = (StartMessage) job;
          iniPrice = aIniPrice[proCnt];
          cBiddingPrice = (int) (Math.round( (iniPrice * 1.25) * 0.85)); //초기입찰가격
          msgName = "Bidding Message";
          portName = "bidding_out";
        }
        else if (messageOnPort(x, "result_in", i)) {
          job = x.getValOnPort("result_in", i);
          rm = (ResultMessage) job;
          //System.out.println(
          //    "=======Result Message in from: Auctioneer to:C==========" +
          //rm.cBidPrice);
          resultPrice = rm.cBidPrice;
          if (nStage == 1) { //customer에도 같은 작업
            iniCPE = iniCPE;
          }
          else {
            iniCPE = (int) ( (double) iniCPE * (double) 0.99);
            // 원래는 * 0.9지만 몇 차례 입찰 후 iniCPE가 0이 되어 입찰이 진행되지 않기 때문에 변경
          }
          cBiddingPrice = resultPrice + ( (int) (Math.random() * iniCPE)); //새로운 입찰가격
          //      System.out.println(
          //          "CCresultPrice: " + cBiddingPrice + " =  CCresultPrice :" +
          //          resultPrice + " ((int)(Math.random()*iniCPE)): " +
          //         ( (int) (Math.random() * iniCPE)));
          nStage++; //customer에도 같은 작업
          msgName = "Bidding Message";
          portName = "bidding_out";
        }
        else if (messageOnPort(x, "terminate_in", i)) {
          job = x.getValOnPort("terminate_in", i);
          //    System.out.println("terminate Message in**********");
          tm = (TerminateMessage) job;
          cBiddingPrice = 0;
          proCnt++; //한 개 상품에 대한 입찰 종료, 다음상품 경매
          //   System.out.println("한 개 상품에 대한 입찰 종료, 다음상품 경매********");
          if (proCnt >= aIniPrice.length) {
            proCnt = 0;
          }
          msgName = "ACK Message";
          portName = "ACK_out";
        }
        holdIn("active", cPTime);
      }
    }
  }

  public void deltint() {
    passivate();
    job = new entity("none");
  }

  public void deltcon(double e, message x) {
    deltint();
    deltext(0, x);
  }

  public message out() {
    message m = new message();
    if (msgName == "Bidding Message") {
      content con = makeContent(portName,
                                new BiddingMessage(msgName, cBiddingPrice));
      m.add(con);
      // System.out.println("Customer Bidding Message out***************" +
      //                   cBiddingPrice);
    }
    else if (msgName == "ACK Message") {
      content con = makeContent(portName, new BiddingMessage("ACK Message"));
      m.add(con);
      //System.out.println("Customer ACK Message out***************");
    }
    return m;
  }

  public void showState() {
    super.showState();
    System.out.println("job: " + job.getName());
  }

  public String getTooltipText() {
    return
        super.getTooltipText()
        + "\n" + "job: " + job.getName();
  }
}

//StartMessage.java
// 2009. 06. 01
// Modified by Aettie Ji

package SimpArc;

import genDevs.modeling.*;
import genDevs.simulation.*;
import GenCol.*;

public class StartMessage // 새로운 상품의 경매 시작 알림
    extends entity {

  public StartMessage(String name) {
    super(name);
  }
}

// BiddingMessage.java
// 2009. 06. 01
// Modified by Aettie Ji

package SimpArc;

import genDevs.modeling.*;
import genDevs.simulation.*;
import GenCol.*;

public class BiddingMessage
    extends entity {

  public int nBiddingPrice; //입찰가격

  public BiddingMessage(String name) {
    super(name);
  }

  public BiddingMessage(String name, int nBiddingPrice) {
    super(name);
    this.nBiddingPrice = nBiddingPrice;
  }
}


// ResultMessage.java
// 2009. 06. 01
// Modified by Aettie Ji

package SimpArc;

import genDevs.modeling.*;
import genDevs.simulation.*;
import GenCol.*;

public class ResultMessage // 입찰 결과 메시지
    extends entity {

  public int sBidPrice; // supplier 입찰가격
  public int cBidPrice; // customer 입찰가격

  public ResultMessage(String name) {
    super(name);
  }

  public ResultMessage(String name, int cBidPrice, int sBidPrice) {
    super(name);
    this.sBidPrice = sBidPrice;
    this.cBidPrice = cBidPrice;
  }
}


// TerminateMessage.java
// 2009. 06. 01
// Modified by Aettie Ji

package SimpArc;

import genDevs.modeling.*;
import genDevs.simulation.*;
import GenCol.*;

public class TerminateMessage // 해당 상품의 경매 종료 알림
    extends entity {

  public int terminatePrice; // 낙찰가격

  public TerminateMessage(String name) {
    super(name);
  }

  public TerminateMessage(String name, int terminatePrice) {
    super(name);
    this.terminatePrice = terminatePrice;
  }
}


저작자 표시 비영리 변경 금지
Creative Commons License
Creative Commons License
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)

  • limitation of ILP - Benchmark, HW와 compiler가 복잡해짐. 현존하는 시스템에서 ILP가 얼마나 실현가능한가? (비용이 늘어난다), 프로세서 성능 커브를 유지하기 위한 새로운 HW/SW 메카니즘을 개발할 필요가 있는가?

--> 컴파일러 기술의 발달과 새로운 다른 하드웨어 기술이 한계를 극복하게 할 수 있다.

  • Thread level parallelism

    • 원래부터 parallel한 execution의 multi thread를 사용하여 명시적으로 표현된다. multiple instruction scheme을 사용하여 많은 프로그램을 돌리는 컴퓨터의 throughput을 높이고, multi-thread program의 실행시간을 줄이는데 목적이 있다. ILP에 비해 비용적으로 효울적이다.
    • multithreaded execution: 멀티 쓰레드가 오버랩을 통해 한 개 프로세서의 FU를 공유한다.; 프로세서는 각 쓰레드의 독립적 state를 복제한다. (PC나 register등을 각각 유지), 가상 메모리를 통한 공유 메모리는 이미 다중 프로세서에 의해 제공된다. 그리고 빠른 쓰레드 스윗치를 위한 하드웨어
    • 언제 스윗치 되나? 쓰레드 당 인스트럭션이 변경되었을 때(fine grain), 캐시 미스등의 이유로 쓰레드가 stall되었을 때(coarse grain), 다른 쓰레드가 실행될 수 있다.
    • Fine-grained multithreading

      각 인스트럭션에 대해서 쓰레드 간 스윗치가 발생, multiple thread의 실행이 interleaved된다. round-robin으로 수행되는 경우가 많고, 쓰레드 stall은 스킵된다. CPU는 클락마다 쓰레드를 스윗치할 수 있어야 한다. 한 개의 쓰레드가 stall되면 다른 쓰레드의 인스트럭션이 수행되므로 short, long stall을 모두 숨길 수 있다.stall 없이 대기중인 쓰레드가 다른 쓰레드로 인해 stall될수 있기 때문에 개개의 쓰레드의 실행속도를 느리게 할 수 있다. Sun의 niagara에서 사용

    • Coarse-grained multithreading

      L2 캐시의 미스 등과 같이 비용이 많이 드는 stall의 발생시에만 쓰레드를 스윗치한다. 매우 빠른 스윗칭을 할 필요가 줄어든다. 중대한 stall 발생시에만 스윗치하기 때문에 다른 쓰레드로 인해 실행이 느려지지 않는다. pipeline start-up 에서 발생하는 짧은 stall로 인해 발생하는 throughput loss를 극복하기 어렵다. CPU가 한개의 쓰레드로부터만 인스트럭션을 이슈하기 때문에, stall이 발생하면 파이프라인이 비거나 중단된다. 인스트럭션이 완료되기 전에 새로운 쓰레드가 파이프라인을 채워야 한다. 이 비용보다 stall에 대한 소모비용이 더 큰 경우에 유리하며, IBM AS/40에서 사용

  • Simultenance Multithreading (SMT)

    • 다이나믹하게 스케줄된 프로세서가 멀티 쓰레딩을 지원하는 HW 메카니즘을 이미 가지고 있다고 하면, 독립적인 쓰레드의 레지스터 셋을 유지하기 위해 대량의 가상 레지스터가 사용된다. 레지스터 renaming은 유일한 레지스터 구분자를 제공하며, 다중 쓰레드로부터 온 인스트럭션은 쓰레드 간의 소스와 데스티네이션의 혼란 없이 데이터패스에서 섞일 수 있다. out-of-order completion 은 더 좋은 HW 활용도를 위해 쓰레드가 순서를 뒤바꿔 수행하는 것을 허용한다.
    • 쓰레드 renaming table을 추가하고, 서로 구분된 PC를 유지한다. 각 쓰레드의 구분된 ROB를 유지하여 독립적인 commitment가 지원되도록 한다.
    • design challenges

      SMT은 fine-grained implementation에서만 가능하기때문에 fine-grained scheduling이 단일 쓰레드의 성능에 미치는 영향은, 선호하는 쓰레드 접근방법은 throughput과 단일 쓰레드 성능을 감소시키는가? 선호쓰레드 방법은 그 선호 쓰레드가 stall될때 프로세서가 일부 throughput을 희생시킬 가능성이 있다. 다중 컨텍스트를 유지해야 하는 큰 레지스터 파일, 인스트럭션 이슈나 완료(commit)할 때 클락 사이클에 영향을 주지 않아야한다. SMT에 의해 생성된 TLB가 cache와 일으킬 수 있는 충돌이 성능을 저하시키지 않을 것을 보장해야 한다.

이 글은 스프링노트에서 작성되었습니다.

Creative Commons License
Creative Commons License
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)

  • Funtion unit은 분산되어 있으며, FU buffer는 reservation station이라 칭하고, operand를  pending한다. operand의 value가 확정되면 그 값을, 확정되기 이전에는 그 값이 들어갈 pointer를 저장한다. WAR, WAW harzard를 방지하기 위해 레지스터를 renaming한다. 레지스터 수보다 많은 reservation station이 가능하다. (컴파일러는 레지스터 갯수내에서만 optimazation이 가능), RS로 부터 FU로 값이 전달되는데, 이때 레지스터를 통해서가 아니라 common data bus를 이용해서 모든 FU에 알려진다. operand가 사용가능할 때마 인스트럭션을 수행하므로 RAW harzard가 방지된다. load, store도 FU에 의해 관리, integer와 floating point 인스트럭션을 분리

    사용자_지정_16.png

    Reservation station components

    Op: operation to perform in the unit

    Vj, Vk: value of source operands: store buffer에 V field가 있으며, 결과가 저장된다.

    Qj, Qk: Reservation station producing source register; 값이 쓰여질 소스 레지스터를 생성, 0이면 ready, store buffer는 Qi, RS에서 생성된 결과를 위한 변수를 갖는다.

    Busy: indicates RS or FU is busy

     

    register result status: 어떤 FU가 각 레지스터에 write할 것인가를 나타낸다. 레지스터에 쓰여질 pending instruction이 없으면 blank

    Tomasulo algorithm의 3단계

    1. Issue: FP op queue로부터 인스트럭션을 얻는다. -> RS이 free라면 (no structural hazard), control은 인스트럭션을 issue하고, 오퍼랜드를 보낸다. (rename register)
    2. Execute: operate on operands -> 양쪽의 operand가 모두 ready일 때 실행; ready가 아니면 common data bus로부터 결과가 전달되기를 기다린다.
    3. Write result: finish execution -> CDB에 값을 쓰고 모든 대기중인 unit에 결과를 전달한다. RS가 available한 것을 표시
    • normal data bus: data + destination
    • common data bus: data + source ;64bit of dada and 4bit FU address, 여러 FU가 있기때문에 어디서 왔는지 표시, FU와 맞는 것이 있으면 write(produces results), broadcast
    • example speed: FP +,-; 2 cycles, *; 10 cycles, LD; 1 cycle, /; 40 cycles

    예제

    1.JPG

  • LD inst issue load buffer; busy와 address register status; F6의 값이 load1에 의해 나올 것임을 기술 

  • 3.JPG
  • LD  inst issue load 2 busy, 목적주소 저장 F2의 값이 load2에 의해 만들어짐을 저장 multiple load 가능

    4.JPG

    Multd issue되고 , RS의 FU에 기록,

    R(F4)는 source operand

    load2에 의해서 나올 F2의 값을 기다려야 함을 기록,

    F0은 Multi1에 의해 생성됨을 기록

    RS에서는 레지스터의 이름이 저장되지 않는다.

    LD는 1 cycle이 소비된다고 가정했으므로 load1 complete


  • 5.JPG

  • SUBD issue, load1 해제

    load1이 완료되어 register write( F6)되어 값을 얻었으므로, M(A1)은 바로 read할 수 있다.

    load2는 아직 결정되지 않았으므로 기록함 


  • 6.JPG

  • load2가 완료되어 F2값이 결정되었고, 이제 MULTD와 SUB의 실행이 가능해진다.

  • SUB는 2 cycle이 실행에 소비되므로 time = 2, MULTD는 10 cycle이 소비되므로 time =10

     7.JPG

     

  • 8.JPG

  •  9.JPG

  • 10.JPG

  •  11.JPG

  •  12.JPG


  • 13.JPG


  • 14.JPG


  • 15.JPG

  • 16.JPG

  • 17.JPG

  • 18.JPG

  • 19.JPG


  • 20.JPG



    • register renaming; 각 iteration에서 레지스터를 위해 서로 다른 물리적 공간을 사용한다. (dynamic unrolling)

      RS는 이전의 integer control flow op를 앞서 inst를 issue할 수 있도록 하며, 레지스터의 old value의 buffer 역할을 하기 때문에 WAR hazard를 막을 수 있다.

    • hazard detection logic이 분산되어 있다. -> distributed RS, CDB, 여러 인스트럭션이 하나의 값을 기다리고 있고, 서로 다른 각각의 operand를 갖고 있다면, 한꺼번에 CDB의 broadcasting에 의해 release될 수 있다, 만약 레지스터 파일이 분산되어 있지 않고, 현재 사용중이라면, 레지스터가 available해질 때까지 기다렸다가 결과값을 읽어야 한다. FP op가 끝나는 시간이 다르기 때문에, WAW와 WAR hazard를 막을 수 있다.
    • Drawbacks-> 복잡도가 높다. 많은 연관된 store가 빠른 속도로 일어난다. CDB에 의해 성능이 좌우된다. 불명확한 interript 발생 가능

     

    • Speculation to greater ILP

      • 추측이 항상 정확하다는 가정하에 brance의 결과를 추측하고 프로그램을 실행하여 control dependency를 극복: branch prediction이 항상 정확하다는 가정하에 fetch, issue, execute, dynamic scheduling은 fetch와 issue만 다룬다.
      • data flow execution model: operand가 available해지자마자 operation을 실행
      • 3가지 component; dynamic branch prediction, control dependency가 해결되기 전에 인스트럭션을 수행할 수 있도록 하는 speculation(+부정확한 speculated sequence를 undo할 수 있는 능력), basic block의 서로 다른 combination을 스케줄링하기위한 dynamic scheduling
      • branch가  항상 taken되었다고 가정하고 실행하기 때문에, commit stage를 두어 완료된 inst가 프로그램에 반영되어야 하는가를 결정한다. (branch untaken일 경우 반영되면 안된다.) inst가 더이상 speculative하지 않을 때 레지스터나 메모리를 갱신한다. Reorder buffer(ROB)는 완료된 후 commit을 기다리는 버퍼를 사용하며, 이 버퍼는 speculated될 수 있는 인스트럭션에 result를 pass하는 역할도 한다.
      • ROB field; inst type, destination, value(commit 되기 전까지 inst의 result저장), ready(value의 ready여부), FIFO
      • Tomasulo algorithm with speculation의 4단계

        • 1.Issue: FP op queue로부터 인스트럭션을 얻는다. -> RS이 free라면 (no structural hazard), control은 인스트럭션을 issue하고, 오퍼랜드를 보낸다. (rename register)
        • Execute: operate on operands -> 양쪽의 operand가 모두 ready일 때 실행; ready가 아니면 common data bus로부터 결과가 전달되기를 기다린다.
        • Write result: finish execution -> CDB에 값을 쓰고 모든 대기중인 unit에 결과를 전달한다. RS가 available한 것을 표시
        • Commit: reorder result로 레지스터 업데이트 - > head의 inst의 result를 register에 저장하고 remove, misprediction이 발생하면 버퍼를 비운다.
      •  

        r1.JPG
        r2.JPG
        r3.JPG
        r4.JPG
        r5.JPG
        r6.JPG
        r7.JPG



      메모리 hazard 방지하기

      실제 update는 원래 프로그램 순서대로 되기 때문에, WAW, WAR hazard는 발생하지 않는다. RAW의 경우, store inst를 갖는 active ROB entry가 있고, 이 store의 destination field와 match되는 load의 A filed가 있다면, load의 실행의 2번째 step을 초기화하는 load를 허용하지 않는다. 모든 이전의 store에 대한 load의 유효주소의 계산을 위한 프로그램 순서를 유지한다. 이렇게 하면, 이전의 store에 의해 쓰여진 메모리 위치를 접근하려고 하는 load는 store가 데이터를 모두 쓸때까지 매모리접근을 허용하지 않도록 보장한다.

    • FU가 한개이면 CPI는 1보다 크다. 여러개의 프로세서를 동적으로 스케줄하여 사용하거나, 여러개의 프로세서를 다이나믹하게 스케줄링하거나, VLIW(very ling instruction word)를 사용한다.
    •  

      이 글은 스프링노트에서 작성되었습니다.

  • Creative Commons License
    Creative Commons License
    이 내용을 참고하시기 전에...
    시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
    책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
    (그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
    (언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)

    • What is Instruction Level Parallelism?

      성능을 향상시키기 위해 이스트럭션의 실행을 오버랩하는 것, 하드웨어가 다이나믹하게 패러럴리즘을 발견하고 활용하는 것에 의존하는 방법과, 컴파일 타임에 패러럴리즘을 동적으로 발견하는 소프트웨어 기법을 사용하는 방법이 있다. 프로그램에서 베이직 블럭이 차지하는 비율이 적으므로, 성능향상을 위해서는 loop level parallelism이 필요하다. 이를 위해서는 loop unrolling되어야 하는데, 다이나믹하게 branch를 prediction하거나, 컴파일러에 의해 static하게 unrolling할 수 있다. loop level parallelism에서 인스트럭션의 dependency를 정하는 것은 매우 중요하다. 만약 두 개의 인스트럭션이 parallel 하다면, 이는 임의의 depth의 파이프라인에서 어떤 stall도 발생시키지 않으면서 동시에 실행될 수 있음을 의미한다. 또한 dependent 하다면, 이는 부분적으로 오버랩되더라도 병렬적이지 않고, 순서대로 실행되어야 함을 의미한다.

    • Dependency and harzards

      • data dependency

        I: add     r1, r2, r3
        J: sub     r4, r1, r3

        J instruction이 I가 write하기 전에 I의 피연산자를 read하려고 시도한다. J는 I에 의존적이다. 혹은 K 인스트럭션이 I에 의존적이라면, J도 K에 의존적이다. 이러한 경우 동시 실행이 불가능하고, RAW harzard를 발생시킬 수 있다. 하드웨어나 소프트 웨어는 프로그램의 순서를 따라야 하고, 이 의존성은 프로그램의 특성이다. 데이터 의존성은 해저드의 가능성을 갖으며, results가 계산되어야하는 순서를 결정하며, 얼마나 parallelism이 활용될 수 있는지의 upper bound를 정한다. NW/SW의 목적은, 단지 프로그램의 결과에 영향을 줄 수 있는 프로그램 순서만을 지키면서 parallelism을 활용하는 데 있다.

      • name dependency

        두 개의 인스트럭션이 같은 이름의 레지스터나 메모리 공간을 사용하지만(name), 이 name과 연관된 데이터 플로우가 둘 사이에 없는 경우이다. 두 가지 버젼이 있고 rename으로 해결 가능.

        1) anti-dependence: WAR harzard 발생, 레지스터의 이름을 바꿔준다.

        2) output dependence: WAW harzard발생, 역시 레지스터 이름을 바꿔준다.

      • control dependency

        프로그램의 정확성에 영향을 주지 않는다면 순서를 지킬 필요가 없으며, 프로그램 정확성에 중요한 것은 exception behavior와 data flow이다.

      • exception behavior

        인스트럭션 실행의 순서를 변경했을 때 새로운 exception이 발생하지 않도록 해야한다.

        DADDU     r2, r3, r4
        BEQZ      r2, L1
        LW        r1, 0(r2)
        L1:

        r2에 대한 데이터 의존성을 유지하지 않으면 프로그램은 다른 결과를 낸다. 컨트롤 의존성을 무시하고 LW 를 BEQZ 앞으로 옮기면, LW는 memory protection exception을 발생시킬 것이다. (데이터 의존성은 없다.) 만약 branch가 taken되면 이 exception을 무시한다. speculation이나 이외의 SW 기술이 있다.

      • data flow

        데이터 값의 실제적인 flow, beanch가 이 flow를 dynamic하게 만드는데, 어떤 인스트럭션이 data value의 supplier인가는 찾아야 한다.

        DADDU     r1, r2, r3
        BEQZ      r4, L
        DSUBU     r1, r5, r6
        L:
        OR        r7, r1, r8

        branch가 taken되느냐 아니냐에 따라, OR이 의존하는 인스트럭션이 DADDU인지, DSUB인지가 결정된다. data flow는 반드시 지켜져야 한다.

    • Basic Compiler technique for exposing ILP(looping unrolling)

      for (i = 1000; i>0; i = i-1)
      x[i] = x[i] + s;
      위의 loop에 대해서 생각해보자. 이 예제에서는 delayed branch는 무시하고, 다음과 같니 latency를 가정한다.

      결과를 생성하는 인스트럭션 결과를 사용하는 인스트럭션 Latency in cycles stalls between in cycles
      FP ALU op another FP ALU op 4 3
      FP ALU op store double 3 2
      load double FP ALU op 1 1
      load double store double 1 0
      integer op integer op 1 0

    위 코드를 MIPS assembly language로 바꾸면,

    Loop:    L.D    F0, 0(R1) ;F0=array element
    stall 
    ADD.D    F4,F0,F2    ;add scalar in F2
    stall
    stall
    S.D       F4, 0 (R1)     ;store result
    DADDUI    R1, R1, #-8    ;derement pointer 8 byte per DW
    stall
    BNEZ     R1,Loop    ;branch R1!=zero

    4 stall, 9 cycle

    DADDUI의 위치를 ADD.D 앞으로 변경한다.

    Loop:    L.D    F0, 0(R1)    ;F0=array element
    DADDUI     R1, R1, #-8     ;derement pointer 8 byte per DW
    ADD.D     F4,F0,F2     ;add scalar in F2
    stall
    stall
    S.D       F4, 8 (R1)    ;store result //DADDUI가 이동하면서 8로 offset 증가
    BNEZ     R1, Loop    ;branch R1!=zero


    loop의 body를 반복하여 unrolling하는 방법, R1이 4의 배수라는 가정하에 DADDUI와 BNEZ의 반복을 생략하고 마지막에 검사

    대부분 프로그램에서 loop의 upper bound를 모르므로, 이를 n이라고 할 때, k개의 body의 copy를 만든다. 처음 iteration은 n mod k배 수행

    Loop: L.D    F0, 0(R1) ;F0=array element
    stall
    ADD.D    F4,F0,F2   ;add scalar in F2
    2 stalls
    S.D      F4, 0 (R1)    ;store result
    L.D      F6, -8(R1) 
    stall
    ADD.D    F8,F6,F2    ;add scalar in F2
    2 stalls
    S.D      F8, -8 (R1)   ;store result
    L.D      F10, -16(R1)
    stall 
    ADD.D    F12,F10,F2   ;add scalar in F2
    2 stalls
    S.D      F12, -16 (R1)   ;store result
    L.D      F14, -24(R1) 
    stall 
    ADD.D   F16,F14,F2    ;add scalar in F2
    2 stalls
    S.D     F16, -24 (R1)   ;store result
    DADDUI   R1, R1, #-32    ;4*8
    BNEZ  R1, Loop    ;branch R1!=zero

    다음 loop는 n/k 배

    Loop: L.D     F0, 0(R1)   ;F0=array element
    L.D     F6, -8(R1) 
    L.D     F10, -16(R1)
    L.D     F14, -24(R1) 
    ADD.D   F4,F0,F2   ;add scalar in F2
    ADD.D   F8,F6,F2   ;add scalar in F2
    ADD.D   F12,F10,F2   ;add scalar in F2
    ADD.D   F16,F14,F2   ;add scalar in F2
    S.D     F4, 0 (R1)   ;store result
    S.D     F8, -8 (R1)   ;store result
    DADDUI   R1, R1, #32 ;4*8
    S.D     F12, 16 (R1) ;16-32=-16
    S.D     F16, 8 (R1) ;8-32 = -24
    BNEZ  R1, Loop   ;branch R1!=zero



    • loop unrolling에서 5가지 결정해야 할 것

      • loop의 반복이 독립적이라는 것을 발견하여, loop unrolling이 유용하다는 것을 결정하여야 한다.
      • 다른 레지스터를 사용하라, 서로 다른 계산이 같은 레지스터에서 이루어지는 것을 막기 위해서
      • 추가적인 테스트나 branch 인스트럭션, 혹은 loop의 종료나 반복문을 수정하는 것을 줄여라.
      • load나 store를 unrolling할 때는, 서로 다른 반복에서 서로 독립적인가를 관찰한다. 메모리 주소를 분석하여 같은 주소를 참조하는가를 살핀다.
      • 원래 코드와 같은 결과가 나오도록 하는 데 필요한 의존성을 보존하면서 스케줄링한다.
    • loop unrolling의 3가지 한계

      • 감소된 오버헤드는 각 추가적인 unrolling으로 인해 상각된다.
      • code의 크기가 증가
      • 레지스터가 많이 필요하다. 레지스터가 많아지면 컴파일러의 스케줄링도 어려워진다.
      • loop unrolling 은 pipeline에서의 branch의 영향을 줄인다. 다른 한가지 방법은 branch prediction이다.
    • static branch prediction

      • delayed branch. compile time에 static하게 branch를 예측, 이전 run의 정보나, 가장 최근의 run에 기반해서 예측하여 정확성 높임.
    • dynamic branch prediction

      • runtime에 예측, algorithm과 데이터의 regularity, 인스트럭션 시퀀스의 redundancy 이용
      • branch history table(BHT): last time에 branch가 taken 되었는가 표시, 주소체크는 하지 않는다. 1 bit BHT의 경우, loop의 첫번째 iteration과 loop를 나갈 때 2번의 misprediction이 항상 발생
      • 이를 해결하기 위해 2bit BHT 사용: 2회이상 연속되는  status 일때 변경
    • correlated branch prediction

      • m개의 최근에 실행된 branch가 taken인지 untaken인지 기록한다. (m,n) predictor는 일반적으로 m개 last branch를 저장하는데, 2^m history table에서 선택하여, 각 n bit의 counter를 갖는다. global branch history: m last branch의 T/NT status를 저장하는 m-bit shift register, 다른 branch의 taken여부가 현재 branch의 taken여부를 결정하는데 영향을 주는 경우, 같은 branch의 다른 실행 결과도 저장
    • Branch target buffer

      • branch 타겟의 계산은 IF stage에서 stall을 발생시키고, 비용이 든다. BTB는 cache처럼 PC를 저장하는데, match를 찾으면 대응되는 PC를 리턴한다. 만약 branch가 taken되면 그 PC로 프로그램을 계속 진행한다. 현재 주소를 모두 저장해야 한다.
    • Advantage of dynamic scheduling

      • 하드웨어가 stall을 줄이기 위해 인스트럭션 수행을 재구성하는 것으로, data flow와 exception behavior를 지켜야 한다. 컴파일 타임에 dependency를 알 수 없는 경우를 다룬다. miss가 해결되기를 기다리는 동안 다른 코드를 수행함으로서 캐시 미스와 같은 예측하지 못한 딜레이에 대해 프로세서가 대응할 수 있도록 한다. 한 파이프라인에 대해 컴파일된 코드가 다른 파이프라인에서도 효율적으로 수행되며, 컴파일러를 단순하게 한다. HW speculation은 성능을 상당히 향상시키는 기술로 dynamic scheduling이 되어야 가능하다.
      • key idea: stall될 때 관계없는 인스트럭션을 먼저 수행, out-of-order execution, out-of-order complement, 순차적으로 인스트럭션을 가져오나 실행과 완료의 순서를 바꾼다. begins execution과 completes execution을 구분하고 그 사이에 인스트럭션이 execution된다. WAR, WAW를 발생시킬 수 있고, exception를 harder하게 할 수 있다.
      • Dynamic scheduling step 1

        Instruction decode(ID) stage를 Issue: instruction decode와 structural harzard를 체크하는 단계와 Read operands: data harzard가 없을 때까지 대기하다가 operand를 읽는 단계로 나눈다.

         

         

         

    이 글은 스프링노트에서 작성되었습니다.

    Creative Commons License
    Creative Commons License
    이 내용을 참고하시기 전에...
    시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
    책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
    (그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
    (언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)

    • Memory Hierarchy

      사용자_지정_12.png

    • Terminology

      Hit: upper level에 data가 있는 경우

      Hit rate: uppper level에 데이터가 있는 비율

      Hit time: upper level에 access하는 시간 = RAM access time + hit/miss를 결정하는 시간

      Miss: lower level로 부터 데이터를 가져와야 할 경우

      Miss rate =  1- hit rate

      Miss penalty = upper level에 data block을 놓는 시간 + 프로세서로 블럭을 이동하는 시간

      hit time << miss penalty

      average memory access time =  hit time + miss rate * miss penalty

    • Memory hierarchy의 4가지 질문

      • Where can a block be placed in the upper level? (block placement)

        사용자_지정_13.png

      • block 12를 8-block cache에 넣을 경우, 1) fully associative, 아무데나 넣는다. 캐시 활용도 면에서 좋다. 그러나 모든 block을 체크해야 하므로 HW구현이 어렵다. 2), 3)은 주소를 mod 연산을 이용하여 계산된 자리에 넣는다. check하기 쉬우나 miss 발생 가능성이 높다. 4-way정도로 구현한다.

      • How is a block found if it is in the upper level? (block identification) cache의 어느 위치에 데이터가 있는가,..원래 데이터의 주소로 access할 수 있어야 한다.cache가 address tag를 갖고 있어서, 원래 주소를 알 수 있도록 한다.
      • How is a block found if it is in the upper level? (block identification) cache의 어느 위치에 데이터가 있는가,..원래 데이터의 주소로 access할 수 있어야 한다.cache가 address tag를 갖고 있어서, 원래 주소를 알 수 있도록 한다.
      • which block should be replaced on a cache miss?

        Random, Least-recently First(LRU), FIFO,

      • What happens on a write?

        Write-through: cache block, lower-level memory에 동시에 쓴다. cache write이 발생할때마다 memory update, 구현과 디버깅이 쉽다. cache는 항상 clean하며, read miss가 lower level에 write하도록 하는 일이 발생하지 않는다. lower level이 가장 최신의 데이터를 갖기 때문에 data coherancy가 유지된다.

        Write-back: cache만 업데이트하다가, cache를 나갈 때 lower level을 업데이트한다. write이 cache의 속도로 이루어지며, 반복적으로 lower level에 write하는 것을 줄일 수 있다. 적은 메모리 BW를 사용한다. multiprocessor, embedded application에 좋다.

        Write-through의 단점을 보완하기 위해 Write buffer 사용, 낮은 레벨 메모리에 쓰는 것을 기다리느라 CPU가 stall하기 때문에 사용한다. 대량 write가 발생하는 일이 많기때문에 한개의 레지스터가 아닌 버퍼를 사용한다. RAW harzard 발생 가능, next read 이전에 버퍼를 비우던가, read first after check scheme을 사용한다.

    • 6 cache optimazations

      • Reducing miss rate - larger block size(compulsory missas), larger cache size(capacity misses), higher associative(conflict misses)
      • Reducing miss penalty - multilevel caches
      • Reducing hit time - giving priority to read misses over writes, avoding address translation during indexing of the cache
    • Virtual memory(virtual address space)

      모든 프로그램은 물리적인 하나의 주소공간을 공유한다. 사용자 프로그램은 가상 주소 공간에서 돌아가도록 되어 있는데, address translation HW는 OS가 가상 주소와 물리적 메모리를 map하도록 한다.

      • 세 가지 장점

        • translation: 물리적 공간이 뒤섞여 있더라도 프로그램은 메모리를 일관성있는 관점으로 볼 수 있다. 멀티쓰레딩을 가능하게 한다. 프로그램의 가장 중요한 부분만이 물리적 메모리에 존재해야 한다. 스택과 같은 계속적인 구조는 현재 필요한 만큼만 사용한다.
        • protection: 서로 다른 쓰래드에 대해 서로를 보호된다. 다른 페이지가 서로 다른 일을 한다(read only, invisible to user program), ㅋ널 데이터는 사용자 프로그램으로부터 보호된다. 악의적인 프로그램으로부터의 보호
        • sharing: 같은 물리적 공간을 여러 사용자에게 공유하게 할 수 있다(shared memory).
      • virtual address space는 page라고 불리는 메모리 블럭으로 되어있다. 페이지 테이블은 virtual page number와 physical frame을 map한다.

        사용자_지정_14.png

      • Translation lookaside buffer

        가상 주소의 변환 속도를 증진시키기 위한 CPU buffer의 하나로, 페이지 테이블 엔트리를 갖는 고정된 갯수의 slot을 갖고, 각 엔트리는 물리주소와 mapping된다. 메인 메모리안에 해당 페이지나 세그먼트가 있는지 체크하는 데 사용.

        사용자_지정_15.png

     

    이 글은 스프링노트에서 작성되었습니다.

    Creative Commons License
    Creative Commons License

    이 내용을 참고하시기 전에...
    시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
    책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
    (그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
    (언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)

    교재의 Appendix A에 해당하는 부분.

     

  • RISC(Reduced Instruction Set Computer) instruction set의 기본

    • 데이터에 대한 모든 오퍼레이션은 레지스터 안에 있는 데이터에 적용되며, 일반적으로 전체 레지스터를 변경한다. (32 or 64 bits per register)
    • 메모리에 영향을 주는 오퍼레이션은 load와 store, full register 크기보다 작은 크기의 데이터를 load하거나 store할 수 있다.
    • 인스트럭션 포맷은 매우 적고, 크기는 일정하다. ALU instruction: 두 레지스터의 값을 직접 연산하여 다른 레지스터에 저장, Load and Stroe, branches and jumps
  • Simple implementation

    • Instruction Fetch cycle(IF): program counter값에 따라 메모리의 인스트럭션을 fetch, pc는 4씩 증가
    • instruction decode/register fetch cycle(ID): 인스트럭션을 decode하고 레지스터를 읽는다.
    • execution/effective address cycle(EX): ALU

      • memory reference
      • register-register ALU instruction
      • register-immediate ALU instruction
    • memory access(MEM): 유효주소로부터 load하거나 store함
    • write-back cycle
  • classic 5 stage pipelining

    5stage.JPG

    1.JPG

  • basic performance issue

    파이프라이닝은 CPU instruction throughput을 증가시킨다, 즉 타임 유닛당 완료된 인스트럭션의 갯수가 늘어난다. 그러나 각각의 인스트럭션의 수행 속도가 빨라지는 것은 아니다. 사실 파이프라이닝을 컨트롤하기 위한 오버헤드가 오히려 약간 추가된다.

    --실행 속도 gain 예제: 1ns clock cycle일 때, 4 cycle을 ALU op와 branch에, 5cycle을 mem op에 사용한다. 각 40%, 20%, 40%의 빈도로 발생한다고 하고, clock skew와 setup때문에 발생하는 오버헤드로 인한 clock add가 0.2ns일 때, 파이프라이닝으로 얻어지는 speed up은?

    파이프라이닝하지 않았을 때의 평균 인스트럭션 수행시간 = clock cycle * average CPI

    = 1 ns * ((40%+20%)*4 + 40%*5) = 4.4 ns

    파이프라이닝의 clock는 가장 느린 스테이지 + 파이프라이닝 오버헤드, 1ns + 0.2 ns이다.

    speedup = 4.4 ns / 1.2 ns

  • pipeline hazard

    지정된 클락 사이클에 다은 인스트럭션이 실행될 수 없는 상황이 발생한다. 이 harzard는 파이프라이닝이 얻을 수 있는 이상적인 speedup을 감소시킨다.

    • harzard에 의해서 발생되는 파이프라인의 대기상태를 stall이라고 하는데, stall 발생 시의 speedup 계산 방법을 먼저 살펴보자.

      speedup_pipelined = average instruction time_unpipelined/average instruction time_pipelined

      =CPI_unpipelined*clock cycle_unpipelined / CPI_pipelined * clock cycle_pipelined

      파이프라이닝의 이상적인 CPI 는 1이다. CPI_pipelined = 1 + pipeline stall clock cycle per instruction

      speedup = CPI unpipelined / 1 + pipeline stall clock cycle per instruction

      unpipelined CPI가 pipeline depth와 같을 때 speedup = pipeline depth / 1 + pipeline stall clock cyce per instruction

      pipelining으로 clock cycle이 향상되었을 때, speedup = (1 / 1 + pipeline stall clock cyce per instruction) * clock cycle unpipelined / clock cycle pipelined

      clock cycle unpipelined / clock cycle pipelined =  pipeline depth

      stall이 없는 경우, speedup은 pipeline stage의 갯수와 같다.

    • Structural Hazard

      하드웨어가 오버랩된 실행 인스트럭션의 모든 가능한 컴비네이션을 동시에 제공할 수 있는 것이 아닐 경우 발생

      가장 흔히 functional unit이 fully pipelining되지 않았을 때 발생, 해당 unit을 사용하는 instruction의 경우 클락사이클 당 한번의 비율로 진행을 멈춰야한다.

      또 다른 경우는, 리소스가 파이프라인에서 실행되어야 하는 모든 인스트럭션의 컴비네이션을 허용할 만큼 복제되지 않을 때 발생한다. 예를 들어 프로세서가 한 개의 레지스터가 한 개의 write port만 가지는데 한 클락에서 동시에 두개의 write를 시도할 경우 등이다. 필요한 유닛이 사용 가능해질 때까지 stall된다.

      사용자_지정_1.png

      cycle 4에서 Dmem과 Ifetch가 동시에 메모리를 접근해야 하는데, single memory일 경우 그림과 같이 stall이 발생하고 한 cycle이 뒤로 밀린다. 이를 bubble이라고 한다.

      --예제: 데이터 레퍼런스가 40%, ideal CPI가 1, structural hazard가 발생할 때 clock cycle이 1.05배 높아진다고 하면,

      : stall이 없는 경우: average instruction time = CPI * clock cycle time

      : structural hazard 발생시 : (1+0.4*1) * clock cycle time_ideal / 1.05 = 1.3 * clock cycle time_ideal

      structural hazard를 해결하기 위해, 인스트럭션을 위한 separate memory access를 제공한다.:캐시를 데이터와 인스트럭션 캐시로 분리하거나, 인스트럭션을 홀드하기 위한 instruction buffer 를 사용하기도 한다. 그러나, unit을 늘리거나 복제하는데 들어가는 비용이 너무 클 때, 해저드의 발생이 상대적으로 적다면 그냥 둔다.:데이터 캐시와 인스트럭션 캐시 접근을 분리해서 제공하는 경우, 두배의 메모리 BW가 요구되고 pin의 BW도 높아진다. fully pipelined FP multiplier의 경우 너무 맣은 게이트를 소비한다.

    • Data Harzard

      이전 인스트럭션의 실행결과에 현재 실행되어야 하는 인스트럭션이 영향을 받는 경우에 실행결과를 아직 얻을 수 없는 경우

      순서대로 실행되던 인스트럭션이 오버랩되어 발생하는 문제로,

      Read After Write(dependancy)

      DADD   R1, R2, R3     실행 결과는 WB stage에 R1에 쓰여진다.

      DSUB   R4, R1, R5     ID stage에 R1을 읽어야 한다. 즉, 데이터 헤져드를 막지 않으면 DSUB 는 잘못된 값을 읽어 사용한다.

      Write After Read(anti-dependacy)

      sub   r4, r1, r3

      add   r1, r2, r3     r1의 이름을 다시 사용해서 발생, 별로 문제되지 않는다. mips는 5 stage로 read는 항상 2단계에, write는 항상 5단계에 이루어지기 때문에  발생하지 않는다.

      Write After Write (output depecdancy)

      sub   r1, r4, r3

      add   r1, r2, r3    r1의 이름을 다시 사용해서 발생, 역시 모든 인스트럭션이 5단계에 write하는 MIPS에서는 발생하지않는다.

      -- 해결방법 Forwarding

      EX/Dmem이나 Dmem/WB의 결과값인 ALU 결값은 항상 다시 ALU의 input이 된다. 만약 포워딩 하드웨어가 이전의 ALU op가 현재 ALU op를 위한 소스에 대응하는 레지스터에 write한다는 것을 감지한다면, 컨트롤 로직은 레지스터를 읽어오는 것이 아니라 이 forwarded된 결과를 ALU input으로 선택한다. 즉, WB단계까지 가지 않고 ALU 연산이 끝난 상황에서 값을 다음 인스트럭션의 ALU 연산 스테이지에 준다는 얘기다.

       

      사용자_지정_2.png

    • r1의 결과를 기다려야 하므로 data hazrad 발생

  • 사용자_지정_3.png

    forwarding으로 해결

    사용자_지정_4.png

    load와 store연산에서 stall방지, memory에서 memory stage로 값 forwarding



    사용자_지정_6(1).png

    forwarding을 위한 하드웨어 구조





    stall이 발생할 수 밖에 없는 data harzard

    사용자_지정_8(1).png

    lw op는 Dmem cycle까지 데이터를 갖고 있지 않다. sub op는 그 이전 ALU에서 r1의 값을 필요로 하므로 한 cycle stall될 수 밖에 없다.



    • Control Harzard

      branch가 PC를 변경시켜 다음 인스트럭션을 결정할 수 없을 때 발생

      branch가 taken되어도 ID 스테이지가 끝나야 PC가 변경된다. 이미 IF 된 인스트럭션들이 실행되지 않아야 하는 경우가 발생한다.

      일반적인 branch 해결 방법

      branch direction이 clear해질때까지 stall한다.

      branch가 무조건 untaken이라고 가정한다.

      만약 taken되며 인스트럭션을 버린다. 레지스터에 반영되기 이전이기 때문에 프로그램에 영향이 없음. 47%정도는 untaken이라고 한다. PC+4는 원래 계산되어 있는 것이므로 주소 계산을 따로 할 필요가 없다.

      항상 taken이라고 가정한다.

      53%는 taken된다. 그러나 branch target address를 계산할 수 없기 때문에, 이를 위해 1cycle branch penalty 발생, pipeline이 많을 경우 더 많은 cycle 소비, 많은 branch가 taken되는 경우, branch가 늦게 결정되는 경우 유리

      Delayed branch

      뒤따르는 인스트럭션이 수행된 후에 branch된다고 가정한다. (몇 cycle 후에 결정) 컴파일러가 delay slot을 삽입하여 다른 인스트럭션을 삽입하고, branch taken여부는 예측한다. 예측이 잘못되었으면 no-op로 slot을 채운다.

      사용자_지정_9.png

      (a)는 branch와 관계없는 인스트럭션이므로 slot에 삽입. best choice

      (b),(c)의 경우 불가능

      (b)는 add에서 $1의 값이 결정되어야 한다. 이 때 slot에 target 인스트럭션을 넣었는데, branch가 taken될 확률이 높을 때 좋다.

      (c) untaken되었을 때 실행할 instruction을 slot에 넣는다.

      b,c의 경우, 만약 예측하지 않은 방향으로 branch가 되더라도 레지스터에 영향을 주지 않는 범위에서 스케줄되어야 한다. (버려도 값에 영향을 안 주도록)

      파이프라인이 더 깊어지면 한개 이상의 delay slot이 필요하여 비용이 많이 든다. branch target buffer나 branch history등을 활용하여 구현할 수 있다.

      --perfoemance: speedup = pipeline depth/1+pipeline stall cycle from branches=pipeline depth/1+branch frequency*branch penalty

      사용자_지정_10.png

      MIPS 데이터 패스

      Exception과 Interrupt 발생시

      I_i과 I_i+1사이에서 예외나 인터럽트가 발생했을 때, 인터럽트 핸들러는 프로그램을 abort하거나 I_i+1부터 다시 시작해야 한다.

      중요한 것은 메모리나 레지스터에 쓰여지기 이전까지의 인스트럭션 부터 다시 시작해야 한다는 것이다.사용자_지정_11.png

       

    • 이 글은 스프링노트에서 작성되었습니다.

    Creative Commons License
    Creative Commons License

    이 내용을 참고하시기 전에...
    시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
    책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
    (그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
    (언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)

    중간고사는 안 보실 줄 알았는데,

    기말고사 걱정 하면서..이 과목 빡쎄니 이제 슬슬 정리도 하고 준비해야겠는데...하고 있었는데

    이게 왠걸...중간고사라니...ㅜ_ㅜ

    (울어버릴겁니다..ㅜ_ㅜ)

     

    뭐부터 손대야 할지 전혀 모르겠지만,

    어차피 복습 개념으로 천천히 정리를 시작하려고 마음먹었던 거니까

    차분한 마음으로 시작해보자...

     

    우선 Instruction Set Architecture의 개념에 대해서 살펴보자.

    Instruction set architecture는 software와 hardware의 critical interface이다. 좋은 Instruction set architecture abstraction의 조건은 portability, 오랜 세대를 지속해야 하며,generality, 다양한 다른 방법으로 사용될 수 있어야 하며, convenience, 하이레벨에서의 편리한 기능을 제공함과 동시에, efficiency, 로우레벨에서 효율적인 구현이 가능하도록 해야한다. "프로그래머의 관점에서 컴퓨팅 시스템의 attribute, 즉 개념적 구조(conceptual structure)와 기능적 행동(functional behavior)는 데이터의 흐름과 제어 조직, 로직 설계, 물리적인 구현과는 다르다." Amdahl, Blaauw, and Brooks, 1964

    instruction ser architecture가 가져야 할 요소는

    -- 프로그래밍 할 수 있는 storage의 organization

    -- 데이터 타입과 데이터 구조: 인코딩과 표현(representation)

    -- 인스트럭션 형식

    -- 인스트럭션(operation code) 셋

    -- 데이터 아이템과 인스트럭션에 접근하고 어드레싱 할 수 있는 모드

    -- 예외적 조건(exceptional condition)

     

    ISA vs. Computer Architecture

    인스트럭션 셋 디자인은 컴퓨터 구조의 옛날 정의다. 컴퓨터 설계의 다른 일면은 implementation이라 했다. 즉, implemantation에는 덜 비중을 두고 있다는 것을 암시한다. 그러나 우리의 관점은 ISA보다는 CA에 있다. architect의 임무는 단지 instruction set 설계에만 있지않다. 오늘날의 기술적인 장애물은 훨씬 challenging 하다. 컴퓨터 구조의 단지 트랜지스터와 개별의 인스트럭션, 혹은 특정한 구현에 대한 것만은 아니다. 즉, 하드웨어, 런타임 시스템, 컴파일러, OS, application등 완전한 시스템을 제대로 기능할 수 있도록 하는 것이 중요하다.

     

    Quantitative principles of computer design

    1. taking advantage of parallelism

      다중 프로세서나 다중 디스크를 이용하여 서버 컴퓨터의 throughput을 증가시킨다. 예를 들어 carry lookahead adder의 경우, 피연산자 당 비트 수가 linear에서 logarithmic하게 덧셈 속도를 증가시킨다. multiple memory banks는 set-associative cache를 사용하여 병렬적으로 처리한다. pipelining이란, 인스트럭션의 수행을 오버랩하여 하나의 인스트럭션 시퀀스를 수행하는 토탈 시간을 줄이는 것이다. 전통적인 파이프라이닝 5단계는 instruction fetch(Ifetch), register read(Reg), execute(ALU), data memory access(Dmem), register writeReg)이다. pipelining의 한계는, 다음 인스트럭션이 정해진 클럭 내에 수행되는 것을 방해하는 몇가지 hazard에 의해 나타난다. structural hazard는 동시에 서로 다른 일을 하기 위해 같은 하드웨어를 사용하려고 시도할 때 나타난다. data harzard는 어떤 인스트럭션이 아직 pipeline내에 있는 인스트럭션의 결과에 의존할 때 발생한다. control harzard는 인스트럭션의 fetching과 branch나 jump와 같은 control flow에 의해 다음 수행 인스트럭션이 결정되는 것 간의 딜레이에 의해 발생된다.

    2. the principle of locality

      어떤 특정 시간대에 프로그램이 접근하는 주소공간은 상대적으로 작다. 즉, 프로그램이 수행될 때 한 번 사용한 데이터를 또 사용하거나(temporal locality: loop, reuse) 그 주변의 데이터를 곧 접근할 가능성이 많다(spatial locality: straight line code, array access). 

    3. focus on the common case

      common sense를 따른다. 예를 들어 intruction fetch나 decode unit은 multiplier보다 더 빈번히 사용되므로 먼저 optimize한다. 더욱 빈번한 케이스는 종종 더 간단하고, 빠른 시간에 수행된다. 예를 들어, 덧셈에서 오버플로우가 발생하는 경우보다 발생하지 않는 경우가 더 일반적이므로, 발생하지 않는 쪽은 optimize한다. 만약 오버플로우 때문에 딜레이가 발생하더라도, 빈번한 케이스를 optimize했으므로 전체적인 성능은 향상될 수 있다. 컴퓨터의 특정 부분을 향상시킴으로서 얻을 수 있는 퍼포먼스 향상은 Amdahl's law로 계산한다.

    4. Amdahl's Law

      speedup = 증진된 부분을 사용하여 전체 태스크를 수행했을 때의 성능(실행시간)/증진된 부분을 사용하지 않고 전체 태스크를 수행했을 때의 성능(실행시간)

      즉, 원래 시스템에 비해, 특정 부분이 증진된 시스템이 얼마나 빠른가의 비율로 ,

      토탈 60초가 걸리는 프로그램의 20초만이 enhancement를 이용할 수 있다면, Fraction_enhanced는 20/60, 1보다 작거나 같다.

      enhanced mode에서 얻어진 성능의 향상은 speedup_enhanced라고 하며, 원래 5초가 걸리는 program portion이 2초가 걸렸다면 5/2, 항상 1보다 크다.

      enhanced mode를 사용한 original computer의 실행시간은 enhanced 되지 않은 부분을 실행하는 시간 + enhancement를 사용한 부분의 실행시간이다.

      ExTime_{new}&=ExTime_{old}*[(1-Fraction_{enahnced})+\frac{Fraction_{enhanced}}{Speedup_{enhanced}}]

      Speedup_{overall}&=\frac{ExTime_{old}}{ExTime_{new}}&=\frac{1}{(1-Fraction_{enhanced})+\frac{Fraction_{enhanced}}{Speedup_{enhanced}}}

      Speedup_{max}&=\frac{1}{1-Fraction_{enhanced}}

      예제를 풀어보자공...

      -- 새로운 프로세서는 원래 프로세서보다 computation이10배 빠르다. 원래 프로세서의 computation이 40%, IO가 60%라면 overall speedup은?

      Fraction_enhanced = 0.4, Speedup = 10, speedup_overall = 1/((1-0.4)+0.4/10))

      -- 그래픽 프로세서에서 floating point squre root 계산의 실행시간은 20%이다. 첫 번째는 FPSQR 하드웨어를 10% 빠르게 발전시켰을 경우, 두 번째는 인스트럭션의 절반을 차지하는 모든 FP 인스트럭션은 1.6배 빠르게 했을 경우,

      speedup_FPSQR = 1/((1-0.2)+(0.2/10))  = 1/0.82

      speedup_FP = 1/((1-0.5)+(0.5/1.6)) = 1/0.8125 --> 약간 좋다.

    5. the processor performance equation

      CUP time = CUP clock cycles for a program * Clock cycle time

      CUP time = CUP clock cycles for a program / Clock rate

      CPI(Clock Per Instruction) = CUP clock cycles for a program / Instruction count

      -- FP operation 25%

          FP operation의 평균 CPI 4.0 --> 이걸 2.5로 줄이거나

          다른 인스트럭션의 평균CPI 1.33

          FPSQR의 빈도 2%

          FPSQR의 CPI 20 --> 이걸 2로 줄이거나

      CPI_original = 4 * 25% + 1.33 * 75% = 2

      FPSQR은 2% 발생하고, CPI를 20에서 2로 줄였으므로 2.0(original) - (2%*(20-2)) = 1.64

      전체 FP의 평균 CPI를 2.5로 줄였으므로, 75%*1.33 + 25%*2.5 = 1.62 --> 이게 더 좋음.

      CPU time_original/CPU time_new =  speedup_new

      IC * Clock cycle * CPI = CPU time --> instruction count와 clock cycle이 변화 없으면 CPI로 speedup 계산

     

    Trend --> latency에 비해 bandwidth가 비약적으로 발달, memory보다 processor가 발달, 처리할 데이터를 메모리가 공급하지 못함, 이를 해결하는 것이 가장 큰 이슈

    Latency가 bandwidth의 발달에 뒤쳐지는 이유 6가지

    1. Moore의 법칙은 BW에 유리, 즉, 트랜지스터가 빨라지고 갯수가 많아지면 핀이 많아져 BW가 좋아지지만, 상대적으로 데이터를 찾아가는 길이 길어지므로 latency는 덜 좋아진다.
    2. 거리가 latency를 제약한다. DRAM block의 크기가 커지면서 access time이 길어지고, 네트웤상의 컴퓨터의 경우 그 시간이 더 길다.
    3. BW를 늘리는 편이 상업적 광고효과가 크기때문에 많은 리소스가 투자됨.
    4. latency는 BW의 향상을 돕지만 역은 성립하지 않는다.
    5. 게다가 BW는 latency를 해칠 수 있다. queue의 사용, 메모리 모듈을 넓히기 위한 칩의 증가는 BW를 돕지만, latency는 증가시킨다.
    6. OS 오버헤드는 BW보다는 latency에 더 나쁘다.

     

    Define and Quantity

    1. Power

      CMOS chip에서, dynamic power은 동작을 위한 power로 트랜지스터를 스위칭하는데 가장 주요한 에너지가 소비된다.

      Power_dynamic = 1/2 * capacityLoad * voltage^2 * frequencySwitched 

      모바일 디바이스는 에너지를 메트릭으로 한다.

      Energy_dynamic = capacityLoad * voltage^2

      clock rate을 낮추는 것, 즉, frequencySwitched를 낮추는 것은 power는 줄이지만, energy는 줄일 수 없다.

      에너지와 파워를 줄이기 위해 대부분의 CPU는 사용하지 않는 모듈의 clock을 off한다.

      -- voltage 15%의 감소가 15%의 frequency가 감소되게 한다고 하면, 이 때 다이나믹 파워에 미치는 영향은?

      capacityLoad 변화가 없으므로, power_new/power_old = (v*0.85)^2 * (frequencySwitched * 0.85)/ v^2 * freguencySwitched = 0.85^3 = 0.61

      60%만큼 에너지를 줄임.

      트랜지스터가 off상태일때도 소비되는 파워를 static power라 한다.

      power_static = current_static * V

      트랜지스터의 크기가 작으면 갯수가 늘어나기 때문에 손실이 많다.

    2. Dependability

      시스템이 proper하게 작동하고 있다는 것을 어떻게 결정하는가? 네트워크나 파워 서비스가 dependable한가를 보장하기 위해, Service Level Agreement가 제공된다. 시스템은 SLA에 관련해 다음 두가지 상태로 전환된다. service accopmlishment는 SLA에 규정되어 있는 서비스, service interruption은 SLA에 규정되어 있지 않은 상태, failure는 1에서 2상태로 가는것, restoration은 2에서 1상태로 가는 것

      Module reliability 계속적으로 서비스의 수행이 가능한가는 측정(service accomplishment가 지속되는 시간), 혹은 failure되는 시간을 측정, 두 가지 metric이 있다.

      -- Mean Time To Failure(MTTF) = failure간의 시간? billion당 failure수

      -- Failure InTime(FIT) = 1/MTTF, millon 동안의 failure 빈도수

      service interruption은 Mean Time To Repair(MTTR)로 측정

      -- Mean Time Between Failures(MTBF) = MTTF + MTTR

      Module availability = MTTF/(MTTF + MTTR)

      전체 failure rate은 각 모듈의 failure rate을 더한 것--예제: 10disks with 1M hour MTTF, 1 disk controller with 0.5M hour MTTF, 1 power supply with 0.2M hour MTTF일 때 총 FIT와 MTTF

      Failure Rate = 10*(1/1000000) + 1/500000 + 1/200000 = 17/1000000 = 17000 FIT

      MTTF = 1000000000/17000

    3. Performance

      performance(x) = 1/excutionTime(x)

      일반적으로 실제 workload와 벤치마크의 workload를 비교한다. 예측성을 좋게 하기 위해서는 벤치마크의 집합인 벤치마크 suite이 널리 사용되어야 한다. SPECCPU 등, 벤치마크 suite의 여러 벤치마크의 산술평균을 구하면 misreading될 수 있고, product마다 서로 다른 weight를 원할 수 있다. 즉, 상대적인 값이 필요

      SPECRatio, reference computer의 실행시간을 normalize한 것 = time on reference computer/time on computer being rated

      만약 program SPECRatio가 comA가 comB에 비해 1.25배 크다면 A의 performance가 그만큼 좋은 것, 참조 컴퓨터의 값은 없어지므로 아무 컴퓨터나 선택해도 된다.

      산술평균 대신 기하평균 사용 GeometricMean&=\sqrt[n]{\prod_{i=1}^{10}SPECRatio_i}

      기하 평균이 벤치마크 suite의 모든 프로그램의 성능을 모두 반영할 수 없으므로, 평균을 벗어나는 특이한 값들을 표현하기 위해 기하표준편차를 사용한다.

      GeometricMean&=exp(1/n*\sum_{i=1}^nln(SPECRatio_i))

      GeometricStDev&=exp(StDev(ln(SPECRatio_i)))

     

    fallacy: 벤치마크가 유명해지면, 벤치마크에 해당하는 프로그램만 성능을 좋도록 만든다. 주기적으로 변경되어야 한다.

    disk의 rated MTTF는 1200000 hour, 140년에 해당하지만 디스크의 생명은 5년이다. 온도변화나 진동등이 없는 안정된 환경에서만 얻을 수 있는 값이다.

    pitfall: 반드시 평균적인 프로그램의 성능이 골고루 좋아야 되는것은 아니다. 어떤 부분은 fail하더라도 전체 성능에 큰 영향을  미치지 않을 수 있다. power supply등의 경우

     

     

     

     

     

     

     

     

     

    이 글은 스프링노트에서 작성되었습니다.

    Creative Commons License
    Creative Commons License
    사실 내가 작성한 건 아니다...ㅜ_ㅜ
    뭐 수업시간에 따라서 코딩하긴 했지만 장기적으로 찾아온 슬럼프때문에 숙제고 수업이고 잠시 손을 놓았었는데
    다행히 같이 수업을 듣는 명덕이가 다 작성해줬다..ㅋㅋㅋ
    내가 한 건 아니지만 그래도 기록의 의미로 또 포스팅...
    (사실 이번 주엔 발표를 해야되는데...난 어떻게 되고 있는지 전혀 모른다는...미안 명덕 ㅡ,.ㅜ)


    • MinneTAC Model은 TAC SCM 이라 불리는 공급망 관리를 위한 경쟁 에이전트들 중 하나이며 경매 모델과 같은 경제 모델 중 하나이다.
    • 수요자(고객)는 서로 다른 성향을 지니며 각각의 성향에 따라 상품 공급을 요청하고 공급자(에이전트)는 서로 다른 전략을 가지고 중개자를 통해 수요자와의 거래를 성립한다.
    • MinneTAC Model은 4개의 부분(Customer, Broker, Bank, Supplier)으로 구성된다.
    • 3개의 Customer와 1개의 Broker와 Bank, 2개의 Supplier로 구성된다.

    • PROCESS

      1. 각각의 Customer는 자신의 제안 가격(Offer Price) 범위와 제안 요구량(Offer Demand) 범위 내에서 랜덤하게 상품 공급 요청(RFQ)에 대한 가격과 요구량을 제시하고 해당 거래의 만기일(Due Date)을 함께 제시한다.
      2. Broker는 Customer로부터 받은 RFQ를 기반으로 각각의 Supplier의 전략(MaxEProfit, DemandDriven)에 적합한 Customer와 거래를 중개한다. 동시에 요청된 세 개의 상품 공급 요청(RFQ) 중 기대이익(Profit)이 가장 높은 것은 MaxEProfit 전략을 가진 SupplierA와 거래하고 주문량(Demand)이 가장 많은 것은 DemandDriven 전략을 가진 SupplierB와 거래하도록 한다.
      3. 상품 공급 요청(RFQ)을 받은 각각의 Supplier는 거래 만기일(Due Date) 동안 상품을 생산하여 Customer에게 만들어진 상품을 제공한다고 가정하고 해당 거래가 종료된 후 Broker로부터 다음 거래를 할당 받는다.
      4. 각각의 Supplier는 하나의 거래가 종료될 때마다 해당 거래에 대한 순이익(margin)을 얻게 되는데 이것은 Bank에 누적하여 저장한다.
      5. 각각의 Customer는 일정한 주기로 상품 공급을 요청하고 Broker는 Supplier가 상품을 생산하는 동안 다른 상품 공급 요청(RFQ)이 들어오면 2번부터 4번의 과정을 반복한다.
      6. Customer는 총 50번의 상품 공급 요청 (RFQ)을 발생시키며 50번 이상이 될 경우 시스템을 종료한다.


    • PROCEDURE and DESIGN

      DEVS로 구성 시 만들어지는 1개의 Digraph 모델과 4종류의 Component(Atomic Model)와 3종류의 Message로 구성된다.
      • MinneTAC: gpt.java를 수정하여 만든다. (Digraph Model)

      • Customer : genr.java를 수정하여 만든다. Customer는 상품 공급에 대한 요청을 위해 RFQ Message를 Broker에게 전송한다. RFQ Message는 상품 공급이 요청된 시간, 제안 가격, 제안 요구량에 대한 정보가 포함된다. [필수 variables] 제안 가격(offer_price), 제안 요구량(offer_demand)

      • Broker : proc.java를 수정하여 만든다. Broker는 Customer로부터 RFQ Message를 입력 받아 Supplier의 전략에 따라 거래를 진행 할 Customer를 선택하고 해당 Customer의 상품 공급 요청에 대한 정보를 Order Message를 통해 Supplier에게 전달한다. 요청된 상품 공급에 대한 주문은 이전 거래가 완료될 때까지 대기 상태가 되고 이전 거래가 완료되면 순차적으로 처리된다. Broker는 Customer와 Supplier 사이에서 상품 공급 요청을 위한 주문에 대해 중개하는 역할만 한다. 각각의 상품은 시장에서 형성된 실제 시장 가격과 실제 수요량을 기준으로 변화하며 거래 만기일은 Customer의 제안 요구량에 따라 달라진다.
        [필수 variables] 실제 시장 가격(int형 r_price), 실제 수요량(int형 r_demand), 실제 비용(int형 r_cost), 거래 만기일(int형 due_date), 주문 가격(double형 price), 주문 수량(double형 demand), 주문 시간(double형 order_clock), 기대 이익(double형 profit)

      • Supplier : proc.java를 수정하여 만든다. 자신의 공급 전략을 가지고 Broker로부터 해당 전략에 맞는 주문을 요청 받는다. 해당 주문의 거래 만기일 동안 상품을 생산하고 순이익(margin)을 계산하여 Bank에 저장한다. 각각의 Supplier는 주문을 일정 개수까지는 받은 후 순차적으로 처리하고 이후의 주문에 대해서는 주문을 거절한다.
        [필수 variables] 순이익(double형 margin), 받은 주문 가격(double형 a_price), 받은 주문량(double형 a_quantity), 받은 주문의 기대 이익(double형 a_profit), 받은 주문의 거래 만기일(double형 a_due_date), 주문을 받은 시간(double형 in_clock)

      • Bank : proc.java를 수정하여 만든다. 각각의 Supplier로부터 순이익(margin)을 받아 저장해준다.
        [필수 variables] 각 Supplier의 순이익(double형 marginA, marginB)

      • 3 Messages : job.java를 수정하여 만든다.
        RFQ Message: Customer⇒Broker로 전달된다. 상품 공급을 요청하기 위한 메시지로 상품 공급에 대한 요청 시간, 제안 가격, 제안 수량 등의 정보를 포함하며 Broker를 통해 Supplier에게 전달된다.
        [필수 variables] 상품 공급 요청 시간(double형 RFQ_time), 제안 가격(double형 price), 제안 수량(double형 demand)
        Order Message: Customer ⇒ Supplier로 전달되는 메시지로 각각의 Supplier의 전략에 따른 Customer의 주문 정보를 포함한다.
        [필수 variables] 주문 시간(double형 order_time), 주문 가격(double형 price), 주문 수량(double형 quantity), 거래 만기일(double형 due_date)
        Margin Message: Supplier⇒Bank로 전달되는 메시지로 현재 거래에서 발생한 각 Supplier의 순이익(margin)을 저장한다.
        [필수 variables] 순이익(double형 margin)


    // MinneTAC.java
    // modified by Aettie.Ji
    // 2009, May, 5
    
    package SimpArc;
    
    import java.awt.*;
    import simView.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class MinneTAC
        extends ViewableDigraph {
    
      public MinneTAC() {
        super("MinneTAC");
    
        addInport("start");
        addInport("stop");
        addOutport("out");
        addOutport("result");
    
        ViewableAtomic br = new Broker("Broker");
        ViewableAtomic bk = new Bank("Bank");
        ViewableAtomic suA = new MinneSupplier("SupplierA");
        ViewableAtomic suB = new MinneSupplier("SupplierB");
        ViewableAtomic cuA = new MinneCustomer("CustomerA");
        ViewableAtomic cuB = new MinneCustomer("CustomerB");
        ViewableAtomic cuC = new MinneCustomer("CustomerC");
    
        add(br);
        add(bk);
        add(suA);
        add(suB);
        add(cuA);
        add(cuB);
        add(cuC);
    
        addCoupling(br, "P_order_out", suA, "order_in");
        addCoupling(br, "Q_order_out", suB, "order_in");
        addCoupling(cuA, "RFQ_out", br, "RFQ_inA");
        addCoupling(cuB, "RFQ_out", br, "RFQ_inB");
        addCoupling(cuC, "RFQ_out", br, "RFQ_inC");
    
        addCoupling(suA, "margin_outA", bk, "margin_inA");
        addCoupling(suA, "margin_outB", bk, "margin_inB");
        addCoupling(suB, "margin_outA", bk, "margin_inA");
        addCoupling(suB, "margin_outB", bk, "margin_inB");
    
        addCoupling(suA, "product_outA", cuA, "product_in");
        addCoupling(suA, "product_outB", cuB, "product_in");
        addCoupling(suA, "product_outC", cuC, "product_in");
    
        addCoupling(suB, "product_outA", cuA, "product_in");
        addCoupling(suB, "product_outB", cuB, "product_in");
        addCoupling(suB, "product_outC", cuC, "product_in");
    
    	showState();
      }
    
        public void layoutForSimView()
        {
            preferredSize = new Dimension(805, 409);
            ((ViewableComponent)withName("CustomerB")).setPreferredLocation(new Point(367, 113));
            ((ViewableComponent)withName("CustomerA")).setPreferredLocation(new Point(367, 43));
            ((ViewableComponent)withName("Broker")).setPreferredLocation(new Point(-9, 54));
            ((ViewableComponent)withName("CustomerC")).setPreferredLocation(new Point(367, 187));
            ((ViewableComponent)withName("SupplierA")).setPreferredLocation(new Point(-5, 141));
            ((ViewableComponent)withName("Bank")).setPreferredLocation(new Point(363, 265));
            ((ViewableComponent)withName("SupplierB")).setPreferredLocation(new Point(-4, 257));
        }
    }
    


    // MinneCustomer.java
    // modified by Aettie.Ji
    // 2009, May, 5
    
    package SimpArc;
    
    import simView.*;
    
    import java.lang.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    import java.util.*;
    
    public class MinneCustomer
        extends ViewableAtomic {
    
      protected double offer_p;
      protected double offer_d;
      protected entity job;
      protected int offer_num;
    
      // 상품을 받을 때마다 트렉젠션 완료를 위한 거래수를 기록
      public int transaction_numA, transaction_numB, transaction_numC; 
      public Minne_product product_mess;
      public String customer_name;
      public double RFQ_clock, out_t, in_t, delay_t, genr_t, delay_avg_t;
      int count;
    
      public MinneCustomer() {
        this("MinneCustomer");
      }
    
      public MinneCustomer(String name) {
        super(name);
        customer_name = name;
    
        addInport("product_in");
        addOutport("RFQ_out");
    
        // Offer_P, Offer_D
        Random r = new Random(System.currentTimeMillis());
        if (name.equals("CustomerA")) {
          offer_p = (r.nextInt(6) + 9.0) / 10; // 0.9~1.5사이의 랜덤값 생성
          offer_d = (r.nextInt(6) + 2.0) / 10;
        }
        else if (name.equals("CustomerB")) {
          offer_p = (r.nextInt(6) + 6.0) / 10;
          offer_d = (r.nextInt(8) + 5.0) / 10;
        }
        else if (name.equals("CustomerC")) {
          offer_p = (r.nextInt(8) + 2.0) / 10;
          offer_d = (r.nextInt(7) + 9.0) / 10;
        }
      }
    
      public void initialize() {
        transaction_numA = 0;
        transaction_numB = 0;
        transaction_numC = 0;
        count = 0;
        RFQ_clock = 0.9;
        out_t = 0.0;
        in_t = 0.0;
        genr_t = 0.0;
        delay_avg_t = 0;
        product_mess = new Minne_product("product", 0, 0, 0);
        job = new entity("job");
    
        holdIn("active", 50);
        super.initialize();
      }
    
    // 외부 이벤트를 어떤 port를 통해 받을 것인지
      public void deltext(double e, message x) {
        RFQ_clock = RFQ_clock + e;
        Continue(e);
        //if (phaseIs("passive"))
        {
          for (int i = 0; i < x.getLength(); i++) {
            if (messageOnPort(x, "product_in", i)) {
              job = x.getValOnPort("product_in", i);
              product_mess = (Minne_product) job;
              double acc_quantity = product_mess.quantity;
              double acc_due_date = product_mess.due_date;
              genr_t = product_mess.order_time;
              in_t = RFQ_clock;
              delay_t = in_t - genr_t - acc_due_date;
              if (delay_avg_t == 0.0) {
                delay_avg_t = delay_t;
              }
              else {
                delay_avg_t = (delay_avg_t + delay_t) / 2;
              }
    
              if (getName().equals("CustomerA")) {
                transaction_numA++;
              }
              else if (getName().equals("CustomerB")) {
                transaction_numB++;
              }
              else if (getName().equals("CustomerC")) {
                transaction_numC++;
              }
            }
          }
        }
        // phaseIs("active") 일 때는 없음
      }
    
      public void deltint() {
        RFQ_clock += sigma;
        out_t = RFQ_clock;
        count++;
    
        if (count > 50) {
          System.exit(0);
        }
    
        Random r = new Random(System.currentTimeMillis());
        if (name.equals("CustomerA")) {
          offer_p = (r.nextInt(6) + 9.0) / 10; // 0.9~1.5사이의 랜덤값 생성
          offer_d = (r.nextInt(6) + 2.0) / 10;
        }
        else if (name.equals("CustomerB")) {
          offer_p = (r.nextInt(6) + 6.0) / 10;
          offer_d = (r.nextInt(8) + 5.0) / 10;
        }
        else if (name.equals("CustomerC")) {
          offer_p = (r.nextInt(8) + 2.0) / 10;
          offer_d = (r.nextInt(7) + 9.0) / 10;
        }
        if (phaseIs("active")) {
          offer_num++;
          holdIn("active", 50);
        }
        else {
          this.passivate();
        }
      }
    
      public message out() {
        customer_name = this.getName();
        message m = new message();
        content con = makeContent("RFQ_out",
                                  new Minne_RFQ(this.customer_name, out_t, offer_p,
                                                offer_d));
        m.add(con);
    
        return m;
      }
    }
    


    // MinneSupplier.java
    // modified by Aettie.Ji
    // 2009, May, 5
    
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    import simView.*;
    import java.text.*;
    
    public class MinneSupplier
        extends ViewableAtomic { 
      protected double margin;
      protected entity job;
      protected int queue_size, job_loss;
      protected Queue q;
    
      public String customer_nm;
      public String supplier_name;
      public double a_profit, a_profit1;
      public double a_quantity, a_quantity1;
      public double a_due_date, a_due_date1;
      public double probability;
      public int transaction_numA, transaction_numB;
      public double in_clock, in_clock1, out_clock;
      Minne_order order_mess, order_mess1;
      public String pattern;
      DecimalFormat df;
    
      public MinneSupplier() {
        this("MinneSupplier");
      }
    
      public MinneSupplier(String name) {
        super(name);
    
        supplier_name = name;
        pattern = "#.00";
        df = new DecimalFormat(pattern);
        queue_size = 5;
        q = new Queue();
    
        addInport("order_in");
        addOutport("margin_outA");
        addOutport("margin_outB");
        addOutport("product_outA");
        addOutport("product_outB");
        addOutport("product_outC");
      }
    
      public void initialize() {
        phase = "passive";
        sigma = INFINITY;
        job = new entity("job");
        order_mess = new Minne_order("Order", 0, 0, 0, 0);
        out_clock = 0.0;
        transaction_numA = 0;
        transaction_numB = 0;
        probability = 1.0;
    
        super.initialize();
      }
    
      public void deltext(double e, message x) {
        out_clock += e;
        Continue(e);
    
        if (phaseIs("passive")) {
          for (int i = 0; i < x.getLength(); i++) {
            if (messageOnPort(x, "order_in", i)) {
              job = x.getValOnPort("order_in", i);
              order_mess = (Minne_order) job;
              customer_nm = order_mess.message_name;
              a_profit = order_mess.price;
              a_quantity = order_mess.quantity;
              a_due_date = order_mess.due_date;
              in_clock = order_mess.order_time;
    		  // order_in prot로 들어온 order메시지에서 margin을 계산하고
    		  // 주문을 제공한 supplier의 transaction number 증가
              margin = Double.parseDouble(df.format( ( (a_profit - 50) * a_quantity *
                                                      probability)));
              if (supplier_name.equals("SupplierA")) {
                transaction_numA++;
              }
              else if (supplier_name.equals("SupplierB")) {
                transaction_numB++;
              }
              this.holdIn("active", a_due_date);
            }
          }
        }
        else if (phaseIs("active")) {
          for (int i = 0; i < x.getLength(); i++) {
            if (messageOnPort(x, "order_in", i)) {
              entity job1 = x.getValOnPort("order_in", i);
              order_mess1 = (Minne_order) job1;
              a_profit1 = order_mess1.price;
              a_quantity1 = order_mess1.quantity;
              a_due_date1 = order_mess1.due_date;
              in_clock1 = order_mess1.order_time;
    		  // 주문이 queue 사이즈보다 넘치면 job_loss 증가
              if (q.size() < queue_size) {
                q.add(job1);
              }
              else if (q.size() >= queue_size) {
                job_loss = job_loss + 1;
                System.out.println(getName() + " : trade_loss = " + job_loss);
              }
            }
          }
        }
      }
    
      public void deltint() {
        out_clock += sigma;
        if (!q.isEmpty()) {
          order_mess = (Minne_order) q.first();
          customer_nm = order_mess.message_name;
          a_profit = order_mess.price;
          a_quantity = order_mess.quantity;
          a_due_date = order_mess.due_date;
          in_clock = order_mess.order_time;
    
          margin = Double.parseDouble(df.format( ( (a_profit - 50) * a_quantity *
                                                  probability)));
          if (supplier_name.equals("SupplierA")) {
            transaction_numA++;
          }
          else if (supplier_name.equals("SupplierB")) {
            transaction_numB++;
          }
          q.remove();
          this.holdIn("active", a_due_date);
        }
        else {
          this.passivate();
        }
      }
    
      public void deltcon(double e, message x) {
        deltint();
        deltext(0, x);
      }
    
      public message out() {
        message m = new message();
    	// Customer에 따라 product_out port로 product message를 만들어 보낸다.
        if (customer_nm.equals("CustomerA")) { 
          content con1 = makeContent("product_outA",
                                     new Minne_product(this.getName(), in_clock,
              a_due_date, a_quantity));
          m.add(con1);
        }
        else if (customer_nm.equals("CustomerB")) {
          content con1 = makeContent("product_outB",
                                     new Minne_product(this.getName(), in_clock,
              a_due_date, a_quantity));
          m.add(con1);
    
        }
        else if (customer_nm.equals("CustomerC")) {
          content con1 = makeContent("product_outC",
                                     new Minne_product(this.getName(), in_clock,
              a_due_date, a_quantity));
          m.add(con1);
        }
    	// Supplier에 따라 margin_out port로 product message를 만들어 보낸다.
        if (supplier_name.equals("SupplierA")) {
          content con2 = makeContent("margin_outA",
                                     new Minne_margin(this.getName(), margin));
          m.add(con2);
        }
        if (supplier_name.equals("SupplierB")) {
          content con2 = makeContent("margin_outB",
                                     new Minne_margin(this.getName(), margin));
          m.add(con2);
        }
    
        return m;
      }
    
      public void showState() {
        super.showState();
        if (job != null) {
          System.out.println("job: " + job.getName());
        }
      }
    
      public String getTooltipText() {
        return
            super.getTooltipText()
            + "\n" + "job: " + job.getName();
      }
    }
    


    // Broker.java
    
    package SimpArc;
    
    import simView.*;
    import java.lang.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    import java.io.*;
    import java.util.*;
    import java.text.*;
    
    public class Broker
        extends ViewableAtomic {
    
      RandomAccessFile outFile1;
      RandomAccessFile outFile2;
      RandomAccessFile outFile3;
      protected int r_price;
      protected int r_cost;
      protected int random_demand[];
      protected int random_due_date[];
      protected entity job1;
      protected entity job2;
      protected entity job3;
      protected entity job4;
    
      public double profit[];
      public double due_date[];
      public String customer_name[];
      public double price[];
      public double demand[];
      public double quantity[];
      public double order_clock[];
      public String outA, outB;
      public int r_demand;
      public int r_due_date;
      int random_value;
    
      Minne_RFQ customer_mess1;
      Minne_RFQ customer_mess2;
      Minne_RFQ customer_mess3;
    
      Minne_RFQ outport1, outport2;
      public String pattern;
      DecimalFormat df;
    
      public Broker() {
        this("Market");
      }
    
      public Broker(String name) {
        super(name);
        File delFile1 = new File("CustomerA_in_Agent.txt");
        if (delFile1.isFile()) {
          delFile1.delete();
        }
        File delFile2 = new File("CustomerB_in_Agent.txt");
        if (delFile2.isFile()) {
          delFile2.delete();
        }
        File delFile3 = new File("CustomerC_in_Agent.txt");
        if (delFile3.isFile()) {
          delFile3.delete();
        }
    
        try {
          outFile1 = new RandomAccessFile("CustomerA_in_Agent.txt", "rw");
          outFile2 = new RandomAccessFile("CustomerB_in_Agent.txt", "rw");
          outFile3 = new RandomAccessFile("CustomerC_in_Agent.txt", "rw");
          outFile1.writeBytes("============ CustomerA Values ============\n");
          outFile1.writeBytes(getName() + "\t" + "price" + "\t" + "demand" +
                              "\t" + "due_date" + "\n");
          outFile2.writeBytes("============ CustomerB Values ============\n");
          outFile2.writeBytes(getName() + "\t" + "price" + "\t" + "demand" +
                              "\t" + "due_date" + "\n");
          outFile3.writeBytes("============ CustomerC Values ============\n");
          outFile3.writeBytes(getName() + "\t" + "price" + "\t" + "demand" +
                              "\t" + "due_date" + "\n");
        }
        catch (Exception e) {}
    
        addInport("RFQ_inA");
        addInport("RFQ_inB");
        addInport("RFQ_inC");
        addOutport("P_order_out");
        addOutport("Q_order_out");
      }
    
      public void initialize() {
        phase = "passive";
        outA = "SupplierA";
        outB = "SupplierB";
        pattern = "#.00";
        df = new DecimalFormat(pattern);
        sigma = INFINITY;
        customer_mess1 = new Minne_RFQ("customer_message", 0, 0, 0);
        customer_mess2 = new Minne_RFQ("customer_message", 0, 0, 0);
        customer_mess3 = new Minne_RFQ("customer_message", 0, 0, 0);
        outport1 = new Minne_RFQ("out_customer", 0, 0, 0);
        outport2 = new Minne_RFQ("out_customer", 0, 0, 0);
        job1 = new entity("job1");
        job2 = new entity("job2");
        job3 = new entity("job3");
        r_price = 100;
        r_cost = 50;
        random_value = 0;
        random_demand = new int[2];
        random_due_date = new int[2];
        random_demand[0] = 1000;
        random_demand[1] = 10;
        random_due_date[0] = 100;
        random_due_date[1] = 10;
        profit = new double[3];
        due_date = new double[3];
        customer_name = new String[3];
        price = new double[3];
        demand = new double[3];
        quantity = new double[3];
        order_clock = new double[3];
    
        super.initialize();
      }
    
      public void deltext(double e, message x) {
    
        Continue(e);
        Random r = new Random();
    
        random_value = r.nextInt(2);
        if (random_value == 0) {
          r_demand = random_demand[0];
          r_due_date = random_due_date[0];
        }
        else {
          r_demand = random_demand[1];
          r_due_date = random_due_date[1];
        }
    
        if (phaseIs("passive")) {
          for (int i = 0; i < x.getLength(); i++) {
            if ( (messageOnPort(x, "RFQ_inA", i))) {
              job1 = x.getValOnPort("RFQ_inA", i);
              customer_mess1 = (Minne_RFQ) job1;
              customer_name[0] = customer_mess1.RFQ_name;
              price[0] = Double.parseDouble(df.format(customer_mess1.price_rate *
                                                      r_price));
              profit[0] = price[0] - r_cost;
              demand[0] = Double.parseDouble(df.format(customer_mess1.demand_rate *
                  r_demand));
              quantity[0] = demand[0];
              order_clock[0] = customer_mess1.RFQ_time;
              // In High Demand
              if (random_value == 0) {
                if (demand[0] <= 200) {
                  due_date[0] = Double.parseDouble(df.format( ( (r.nextInt(3) + 1.0) /
                      10) * r_due_date));
                }
                else if (demand[0] > 200 && demand[0] <= 500) {
                  due_date[0] = Double.parseDouble(df.format( ( (r.nextInt(5) + 2.0) /
                      10) * r_due_date));
                }
                else if (demand[0] > 500 && demand[0] <= 800) {
                  due_date[0] = Double.parseDouble(df.format( ( (r.nextInt(5) + 5.0) /
                      10) * r_due_date));
                }
                else if (demand[0] > 800 && demand[0] <= 1100) {
                  due_date[0] = Double.parseDouble(df.format( ( (r.nextInt(5) + 8.0) /
                      10) * r_due_date));
                }
                else if (demand[0] > 1100 && demand[0] <= 1300) {
                  due_date[0] = Double.parseDouble(df.format( ( (r.nextInt(4) +
                      11.0) / 10) * r_due_date));
                }
                else if (demand[0] >= 1400) {
                  due_date[0] = Double.parseDouble(df.format( ( (r.nextInt(4) +
                      13.0) / 10) * r_due_date));
                }
                else {
                  due_date[0] = 0.0;
                }
              }
    
              try {
                outFile1.writeBytes(getName() + "\t" + price[0] + "\t" +
                                    demand[0] + "\t" + due_date[0] + "\n");
              }
              catch (Exception ex) {
                System.out.println("Can't write " + ex);
              }
            }
            if ( (messageOnPort(x, "RFQ_inB", i))) {
              job2 = x.getValOnPort("RFQ_inB", i);
              customer_mess2 = (Minne_RFQ) job2;
              customer_name[1] = customer_mess2.RFQ_name;
              price[1] = Double.parseDouble(df.format(customer_mess2.price_rate *
                                                      r_price));
              profit[1] = price[1] - r_cost;
              demand[1] = Double.parseDouble(df.format(customer_mess2.demand_rate *
                  r_demand));
              quantity[1] = demand[1];
              order_clock[1] = customer_mess2.RFQ_time;
              // In High Demand
              if (random_value == 0) {
                if (demand[1] <= 200) {
                  due_date[1] = Double.parseDouble(df.format( ( (r.nextInt(3) + 1.0) /
                      10) * r_due_date));
                }
                else if (demand[1] > 200 && demand[1] <= 500) {
                  due_date[1] = Double.parseDouble(df.format( ( (r.nextInt(5) + 2.0) /
                      10) * r_due_date));
                }
                else if (demand[1] > 500 && demand[1] <= 800) {
                  due_date[1] = Double.parseDouble(df.format( ( (r.nextInt(5) + 5.0) /
                      10) * r_due_date));
                }
                else if (demand[1] > 800 && demand[1] <= 1100) {
                  due_date[1] = Double.parseDouble(df.format( ( (r.nextInt(5) + 8.0) /
                      10) * r_due_date));
                }
                else if (demand[1] > 1100 && demand[1] <= 1300) {
                  due_date[1] = Double.parseDouble(df.format( ( (r.nextInt(4) +
                      11.0) / 10) * r_due_date));
                }
                else if (demand[1] >= 1400) {
                  due_date[1] = Double.parseDouble(df.format( ( (r.nextInt(4) +
                      13.0) / 10) * r_due_date));
                }
                else {
                  due_date[1] = 0.0;
                }
              }
    
              try {
                outFile2.writeBytes(getName() + "\t" + price[1] + "\t" +
                                    demand[1] + "\t" + due_date[1] + "\n");
              }
              catch (Exception ex) {
                System.out.println("Can't write " + ex);
              }
            }
            if ( (messageOnPort(x, "RFQ_inC", i))) {
              job3 = x.getValOnPort("RFQ_inC", i);
              customer_mess3 = (Minne_RFQ) job3;
              customer_name[2] = customer_mess3.RFQ_name;
              price[2] = Double.parseDouble(df.format(customer_mess3.price_rate *
                                                      r_price));
              profit[2] = price[2] - r_cost;
              demand[2] = Double.parseDouble(df.format(customer_mess3.demand_rate *
                  r_demand));
              quantity[2] = demand[2];
              order_clock[2] = customer_mess3.RFQ_time;
              // In High Demand
              if (random_value == 0) {
                if (demand[2] <= 200) {
                  due_date[2] = Double.parseDouble(df.format( ( (r.nextInt(3) + 1.0) /
                      10) * r_due_date));
                }
                else if (demand[2] > 200 && demand[2] <= 500) {
                  due_date[2] = Double.parseDouble(df.format( ( (r.nextInt(5) + 2.0) /
                      10) * r_due_date));
                }
                else if (demand[2] > 500 && demand[2] <= 800) {
                  due_date[2] = Double.parseDouble(df.format( ( (r.nextInt(5) + 5.0) /
                      10) * r_due_date));
                }
                else if (demand[2] > 800 && demand[2] <= 1100) {
                  due_date[2] = Double.parseDouble(df.format( ( (r.nextInt(5) + 8.0) /
                      10) * r_due_date));
                }
                else if (demand[2] > 1100 && demand[2] <= 1300) {
                  due_date[2] = Double.parseDouble(df.format( ( (r.nextInt(4) +
                      11.0) / 10) * r_due_date));
                }
                else if (demand[2] >= 1400) {
                  due_date[2] = Double.parseDouble(df.format( ( (r.nextInt(4) +
                      13.0) / 10) * r_due_date));
                }
                else {
                  due_date[2] = 0.0;
                }
              }
    
              try {
                outFile3.writeBytes(getName() + "\t" + price[2] + "\t" +
                                    demand[2] + "\t" + due_date[2] + "\n");
              }
              catch (Exception ex) {
                System.out.println("Can't write " + ex);
              }
            }
    
            // 각 Agent에 어느 Customer를 보낼지 outport를 결정
            // MaxEProfit
            double max_p = profit[0];
            if (profit[1] >= max_p) {
              if (profit[2] >= max_p && profit[2] >= profit[1]) {
                outA = "CustomerC";
              }
              else {
                outA = "CustomerB";
              }
            }
            else {
              if (profit[2] >= max_p) {
                outA = "CustomerC";
              }
              else {
                outA = "CustomerA";
              }
            }
    
            // DemandDriven
            double max_d = demand[0];
            if (demand[1] >= max_d) {
              if (demand[2] > max_d && demand[2] > demand[1]) {
                outB = "CustomerC";
              }
              else {
                outB = "CustomerB";
              }
            }
            else {
              if (demand[2] > max_d) {
                outB = "CustomerC";
              }
              else {
                outB = "CustomerA";
              }
            }
          } // for문 종료(외부입력 전부 받아들인) 후
    //       System.out.println("11111  " + order_clock[0] + "22222  " + order_clock[1] + " 33333  " + order_clock[2]);
          holdIn("active", 0.0); // 메세지 출력(outport로)시킴
        }
    //     else ;// passive가 아니면
      }
    
      public void deltint() {
        if (phaseIs("active")) {
          passivate();
        }
      }
    
      public message out() {
        message m = new message();
        double m_profit1 = 0.0;
        double m_quantity1 = 0.0;
        double m_due_date1 = 0.0;
        double m_order_time1 = 0.0;
        double m_profit2 = 0.0;
        double m_quantity2 = 0.0;
        double m_due_date2 = 0.0;
        double m_order_time2 = 0.0;
    
        if (outA.equals("CustomerA")) {
          m_profit1 = price[0];
          m_quantity1 = quantity[0];
          m_due_date1 = due_date[0];
          m_order_time1 = order_clock[0];
        }
        else if (outA.equals("CustomerB")) {
          m_profit1 = price[1];
          m_quantity1 = quantity[1];
          m_due_date1 = due_date[1];
          m_order_time1 = order_clock[1];
        }
        else if (outA.equals("CustomerC")) {
          m_profit1 = price[2];
          m_quantity1 = quantity[2];
          m_due_date1 = due_date[2];
          m_order_time1 = order_clock[2];
        }
    
        if (outB.equals("CustomerA")) {
          m_profit2 = price[0];
          m_quantity2 = quantity[0];
          m_due_date2 = due_date[0];
          m_order_time2 = order_clock[0];
        }
        else if (outB.equals("CustomerB")) {
          m_profit2 = price[1];
          m_quantity2 = quantity[1];
          m_due_date2 = due_date[1];
          m_order_time2 = order_clock[1];
        }
        else if (outB.equals("CustomerC")) {
          m_profit2 = price[2];
          m_quantity2 = quantity[2];
          m_due_date2 = due_date[2];
          m_order_time2 = order_clock[2];
        }
    
        content con1 = makeContent("P_order_out",
                                   new Minne_order(outA, m_order_time1, m_profit1,
                                                   m_quantity1, m_due_date1));
        content con2 = makeContent("Q_order_out",
                                   new Minne_order(outB, m_order_time2, m_profit2,
                                                   m_quantity2, m_due_date2));
    
        m.add(con1);
        m.add(con2);
    
        return m;
      }
    
      public void showState() {
        super.showState();
    //    System.out.println("price : " + price);
      }
    
    }
    


    // Bank.java
    // modified by Aettie.Ji
    // 2009, May, 5
    
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    import simView.*;
    
    public class Bank
        extends ViewableAtomic { //ViewableAtomic is used instead
      //of atomic due to its
      //graphics capability
      protected entity job;
      protected double margin_sum1, margin_sum2;
    
      public String supplier_name;
      Minne_margin margin_mess;
      int sell_countA, sell_countB;
    
      public Bank() {
        this("Bank");
      }
    
      public Bank(String name) {
        super(name);
        // 파일로 기록하려면 이곳에 작업을 추가
        addInport("margin_inA");
        addInport("margin_inB");
      }
    
      public void initialize() {
        phase = "passive";
        sigma = INFINITY;
        job = new entity("job");
    
        this.margin_sum1 = 0.0;
        this.margin_sum2 = 0.0;
        this.sell_countA = 0;
        this.sell_countB = 0;
    
        super.initialize();
      }
    
      public void deltext(double e, message x) {
        Continue(e);
    
        if (phaseIs("passive")) {
          for (int i = 0; i < x.getLength(); i++) {
            if (messageOnPort(x, "margin_inA", i)) {
              job = x.getValOnPort("margin_inA", i);
              margin_mess = (Minne_margin) job;
              this.supplier_name = margin_mess.message_name;
              this.margin_sum1 += margin_mess.margin;
              this.sell_countA++;
            }
            else if (messageOnPort(x, "margin_inB", i)) {
              job = x.getValOnPort("margin_inB", i);
              margin_mess = (Minne_margin) job;
              this.supplier_name = margin_mess.message_name;
              this.margin_sum2 += margin_mess.margin;
              this.sell_countB++;
            }
          }
          System.out.println("Bank - margin A : " + margin_sum1);
          System.out.println("Bank - margin B : " + margin_sum2);
          this.holdIn("active", 0.0);
        }
      }
    
      public void deltint() {
        if (this.phaseIs("active")) {
          passivate();
        }
      }
    
      public void deltcon(double e, message x) {
        deltint();
        deltext(0, x);
      }
    
      public message out() {
        message m = new message();
    
        return m;
      }
    
      public void showState() {
        super.showState();
        if (job != null) {
          System.out.println("job: " + job.getName());
        }
      }
    
      public String getTooltipText() {
        return
            super.getTooltipText()
            + "\n" + "job: " + job.getName();
      }
    }
    


    // Minne_margin.java
    // modified by Aettie.Ji
    // 2009, May, 5
    
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class Minne_margin
        extends entity {
      public String message_name; // 메시지 이름
      public double margin; // 마진
    
      public Minne_margin(String mn, double m) {
        super(message_name);
        this.message_name = mn;
        this.margin = m;
      }
    }
    


    // Minne_order.java
    // modified by Aettie.Ji
    // 2009, May, 5
    
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class Minne_order
        extends entity {
      public String message_name; // 메시지 이름
      public double price; // 가격
      public double quantity; // 수량
      public double due_date; // 기한
      public double order_time; // 주문일시
    
      public Minne_order(String mn, double ot, double p,
                         double qty, double dd) {
        super(message_name);
        this.message_name = mn;
        this.price = p;
        this.quantity = qty;
        this.due_date = dd;
        this.order_time = ot;
      }
    }
    


    // Minne_product.java
    // modified by Aettie.Ji
    // 2009, May, 5
    
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class Minne_product
        extends entity {
      public String message_name; // 메시지 이름
      public double quantity; // 상품량
      public double due_date; // 기한
      public double order_time; // 주문일시
    
      public Minne_product(String mn, double ot, double dd,
                           double qty) {
        super(message_name);
        this.message_name = mn;
        this.quantity = gty;
        this.due_date = dd;
        this.order_time = ot;
      }
    }
    


    // Minne_RFQ.java
    // modified by Aettie.Ji
    // 2009, May, 5
    
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class Minne_RFQ
        extends entity {
      public String RFQ_name;
      public double price_rate;
      public double demand_rate;
      public double RFQ_time;
    
      public Minne_RFQ(String RFQ_name, double RFQ_time, double price_rate,
                       double demand_rate) {
        super(RFQ_name);
        this.RFQ_name = RFQ_name;
        this.price_rate = price_rate;
        this.demand_rate = demand_rate;
        this.RFQ_time = RFQ_time;
      }
    }


    설명에는 없는 Product message를 하나 더 만들었는데...
    아..보지 않아서 잘 모르겠다는..ㅋㅋ
    어차피 메시지는 모델간에 정보를 넘겨주는 거기 때문에 안에 가지고 있는 정보가 뭐냐가 중요한 거라는...
    몇 개가 되도 상관은 없다..ㅋㅋ

    저작자 표시 비영리 변경 금지
    Creative Commons License
    Creative Commons License
    Semantic Web 발표를 위해 만든 자료...
    백업의 의미로 저장해 둔다는...
    발표자료는 정말 후딱..거의 하루만에 만들었기 때문에 결코 퀄리티가 높지 않고...
    영어로 발표해야 했기 때문에 대본을 만들어서 거의 읽는 수준이었다는..ㅋㅋㅋ


    요건 참고자료...
    앞 부문은 지금 교재로 쓰고 있는 (말이 좋아 교재지..이 책으로 진도를 나가는 것은 아닌..ㅡ_ㅡ)
    “Semantic Web Technologies”, Davies, J., R. Studer and P. Warren, WILEY
    요 책의 chapter 9를 리뷰한 거고...
    후반부는 NeOn Methodology를 간단하게 소개한 것으로
    NeOn project 홈페이지에 가면 공개되어 있는 자료를 바탕으로 했다.


    http://www.neon-project.org
    NeOn project는 ontology modeling과 life cycle에 대해 아주 전반적이 내용을 다루는 프로젝트라서
    홈페이지를 들어가보면 아주 다양하고 방대한 양의 문서자료를 볼 수 있다.


    급조한 티가 너무 난다는..ㅜ_ㅜ


    저작자 표시 비영리 변경 금지
    Creative Commons License
    Creative Commons License
    이번엔 두 시간에 걸친 옥션 모델 만들기였다...
    아...빡세더라..ㅋㅋ




    Process of Auction Model
    1. Supplier가 Auctioneer에게 판매할 상품의 경매를 요청한다. (이때 상품의 초기 시작 가격 (Initial Price)을 같이 보낸다.) ' 위 그림의 청색 라인이 경매 시작 신호선이다.
    2. Auctioneer는 N개의 Customer에게 Supplier에게 받은 동일한 메시지를 전달하여 경매가 시작 되었음을 알린다. 
    3. 각각의 Customer는 자신만의 가격 탄력성 (Price Elasticity)와 최대 입찰 가능 가격(Maximum Boundary Price)을 가지고 있다. 
    4. 최초의 입찰에서는 각각의 Customer가 입찰 가격으로 Auctioneer로부터 전달 받은 초기 입찰 가격에 자신의 가격 탄력성 안에서 가격을 설정(Rand 함수를 이용하여 자신의 가격 탄력성 안에서 랜덤 하게 선택한다.) 하여 입찰 가격을 정해 Auctioneer에게 보낸다. ->빨간색 점선
      First Bidding Price = Initial Price from Auctioneer + Rand(Price Elasticity of Customer)
    5. 첫 번째 입찰을 받은 Auctioneer는 최초 입찰에서 최고가를 입찰한 Customer와 입찰 최고가를 각각의 Customer 및 Supplier에게 보낸다.
    6. 두 번째 입찰은 Customer가 각각의 자신의 최대 입찰 가격을 넘지 않는 범위에서 최초 입찰 가격에 자신의 가격 탄력성을 더한 가격을 입찰한다. 이미 최초 입찰에서 자신의 최대 입찰 가격을 넘은 Customer는 입찰을 포기(Bidding price = 0) 한다.
      IF (Highest Price of Previous Bidding < Maximun Price Boundary){
           Bidding Price = Highest Price of Previous Bidding + Rand(Price Elasticity of Customer)
      ELSE
           Bidding Price = 0;
    7. 5번을 다시 실행 
    8. 입찰은 총 5회 진행 된다. (※ 5회 이전에 입찰자가 1명만 남은 경우에는 그 입찰자의 입찰가격을 낙찰 가격으로 하고 경매를 종료 시킨다.) 5회 입찰 진행 후 최고가를 입찰한 Customer가 낙찰되며, 낙찰 가격을 모든 Customer와 Supplier에 공지 하고 경매는 종료 된다. 
    9. 경매 종료 메시지를 전달받은 Supplier는 재고에 남아있는 상품의 경매 요청 메시지를 최초 가격과 함께 Auctioneer에게 전달한다. 
    10. 1~9의 과정을 반복하여 supplier에 더 이상 재고가 존재하지 않을 경우 시스템을 종료한다.


    Procedure and Design
    • DEVS로 구성 시 만들어지는 1개의 Digraph 모델과 3종류의 Component(Atomic Model)와 3종류의 Message로 구성된다.
      1. Auction: gpt.java를 수정하여 만든다. (Digraph Model)
      2. Supplier : genr.java를 수정하여 만든다.
        Supplier는 자신의 상품이 저장된 Inventory를 가진다.
        또한, Auctioneer로부터 받은 Result Message를 통해 경매가 종료되었을 경우 Start Message를 전송하여 새로운 상품의 경매를 요청한다.
        [필수 variables] 상품 저장소 (int형 2차원 배열 inventory-상품번호와 시작가격 포함)
      3. Auctioneer : proc.java를 수정하여 만든다.
        Auctioneer는 Supplier로부터 Start Message를 입력받아 경매의 시작을 알린다.
        또한, Customer의 입찰정보를 저장할 리스트를 포함하며 Customer들로부터 Bidding Message를 입력 받아 리스트를 갱신, 최고 입찰자 및 입찰가에 대한 정보를 Result Message를 통해 공지한다.
        [필수 variables] 입찰 리스트 (int형 2차원 배열 bitList - 입찰자와 입찰가격 포함)
        입찰 카운트 (int형 count - 한계값은 5이며 5가 넘을 경우 0으로 셋팅)
        최고 입찰자 (string형 max_bidder), 최고 입찰 가격 (int형 max_price), 낙찰자 (String형 end_bidder), 낙찰 가격 (end_price)
      4. Customer : proc.java를 수정하여 만든다.
        자신의 판매전략에 맞춰 입찰가를 선정하나 만약 선정된 가격이 입찰 한도를 초과할 경우 입찰가를 0으로 조정한다.
        그리고, 만약 경매가 종료되었을 경우에는 Bidding Message를 발생시키지 않고 입찰가를 0으로 재조정한다.
        [필수 variables] 입찰가 (int형 bid_price), 가격 탄력성(int형 PE), 입찰 한도(int형 MBP), 현재가격 (int형 posted_price)
      5. 3 Messages ' job.java를 수정하여 만든다.
        • Start Message: Supplier ' Auctioneer, Auctioneer ' Customer로 전달된다.
          경매 시작을 알리는 메시지로 초기 시작 가격을 가지고 있다.
          [필수 variables] 상품 번호( int형 product_num), 시작가격( int형 initial_price)
        • Bidding Message: Customer ' Auctioneer로 전달되는 메시지로 각 Customer의 정보와 입찰 가격을 포함하고 있다.
          [필수 variables] 입찰자 번호(int형 customer_num), 입찰가격(int형 bidding_price)
        • Result Message: Auctioneer ' Customer, Supplier로 전달되는 메시지로 현재 경매의 진행 상황 및 최고가와 최고가를 입찰한 Customer의 정보를 포함한다.
          [필수 variables] 진행상황(string형 status), 최고가(int형 highest_price), 최고입찰자(string형 highest_bidder)

    Supplier inverntory 내의 10개의 product와 그 초기 가격      1     PD#1     2000
         2      PD#2      2200
         3      PD#3      1800
         4      PD#4      1600
         5      PD#5      2500
         6      PD#6      3000
         7      PD#7      3300
         8      PD#8      2800
         9      PD#9      1900
        10      PD#10     3500

    Customer의 최대 입찰 가격과 입찰 탄력성
         Cus #1      (Initial Price of Product)* 2.0      240
         Cus #2      (Initial Price of Product)* 2.2      220
         Cus #3      (Initial Price of Product)* 1.9      260
         Cus #4      (Initial Price of Product)* 2.4      300
         Cus #5      (Initial Price of Product)* 2.1      280


    총 7개의 파일을 작성했으며, 개략적인 내용은 주석으로 확인하시길...(좀 질렸음...ㅋㅋ)
    어디서 오류가 나는지 잡기 위해서 중간 중간 프린트문을 넣었는데
    모두 주석처리한 채로 그냥 두었다.
    결과는 파일로 출력된다.

    // SingleAuction.java
    // modifued by Aettie Ji
    // April 21st, 2009
    package SimpArc;
    
    import java.awt.*;
    import simView.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class SingleAuction
        extends ViewableDigraph {
      int customer_num = 5;
      double customer_inform[][]; // customer_inform
    
      public SingleAuction() {
        super("SingleAuction");
        customer_inform = new double[customer_num][2]; // customer_inform
        customer_inform[0][0] = 2.0; // 최고입찰가격
        customer_inform[0][1] = 240; // 가격 탄력성
        customer_inform[1][0] = 2.2; // 최고입찰가격
        customer_inform[1][1] = 240; // 가격 탄력성
        customer_inform[2][0] = 1.9; // 최고입찰가격
        customer_inform[2][1] = 260; // 가격 탄력성
        customer_inform[3][0] = 2.4; // 최고입찰가격
        customer_inform[3][1] = 300; // 가격 탄력성
        customer_inform[4][0] = 2.1; // 최고입찰가격
        customer_inform[4][1] = 280; // 가격 탄력성
    
        ViewableAtomic s = new Auction_Supplier("Supplier", 0);
        ViewableAtomic a = new Auctioneer("Auctioneer", customer_num);
    
        for (int i = 0; i < customer_num; i++) {
          String customer_name = "Customer_" + i;
          double MBP = customer_inform[i][0];
          double PE = customer_inform[i][1];
          ViewableAtomic c = new Auction_Customer(customer_name, i, MBP, PE);
          add(c);
          addCoupling(c, "bidout", a, "bidin" + i);
          addCoupling(a, "start", c, "in");
          addCoupling(a, "out", c, "pricein");
        }
    
        add(s);
        add(a);
    
        addCoupling(s, "start", a, "in");
        addCoupling(a, "out", s, "result");
        //    initialize();
        showState();
        /*
          preferredSize = new Dimension(484, 145);
          g.setPreferredLocation(new Point(13, 18));
          p.setPreferredLocation(new Point(195, 18));
          t.setPreferredLocation(new Point(193, 80));
         */
      }
    
      /**
       * Automatically generated by the SimView program.
       * Do not edit this manually, as such changes will get overwritten.
       */
      public void layoutForSimView() {
        preferredSize = new Dimension(816, 409);
        ( (ViewableComponent) withName("Customer_2")).setPreferredLocation(new
            Point(528, 173));
        ( (ViewableComponent) withName("Customer_0")).setPreferredLocation(new
            Point(502, 15));
        ( (ViewableComponent) withName("Supplier")).setPreferredLocation(new Point(
            50, 144));
        ( (ViewableComponent) withName("Customer_1")).setPreferredLocation(new
            Point(520, 105));
        ( (ViewableComponent) withName("Customer_4")).setPreferredLocation(new
            Point(516, 340));
        ( (ViewableComponent) withName("Customer_3")).setPreferredLocation(new
            Point(490, 247));
        ( (ViewableComponent) withName("Auctioneer")).setPreferredLocation(new
            Point(238, 102));
      }
    }


    // Acution_Supplier.java
    // modifued by Aettie Ji
    // April 21st, 2009
    package SimpArc;
    
    import simView.*;
    
    import java.lang.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class Auction_Supplier
        extends ViewableAtomic {
    
      protected double int_arr_time;
      protected int count;
      protected entity job;
      double inventory[][];
      result_message r_msg;
    
      public Auction_Supplier(String name, double Int_arr_time) {
        super(name);
        addInport("result");
        addOutport("start");
        int_arr_time = Int_arr_time;
      }
    
      public void initialize() {
        holdIn("active", int_arr_time);
        job = new entity("job");
        r_msg = new result_message("RESULT", "end", "", 0);
    
        //  phase = "passive";
        //  sigma = INFINITY;
        count = 0;
        inventory = new double[10][2];
        inventory[0][0] = 1;
        inventory[0][1] = 2000;
        inventory[1][0] = 2;
        inventory[1][1] = 2200;
        inventory[2][0] = 3;
        inventory[2][1] = 1800;
        inventory[3][0] = 4;
        inventory[3][1] = 1600;
        inventory[4][0] = 5;
        inventory[4][1] = 2500;
        inventory[5][0] = 6;
        inventory[5][1] = 3000;
        inventory[6][0] = 7;
        inventory[6][1] = 2300;
        inventory[7][0] = 8;
        inventory[7][1] = 2800;
        inventory[8][0] = 9;
        inventory[8][1] = 1900;
        inventory[9][0] = 10;
        inventory[9][1] = 3500;
        super.initialize();
      }
    
      public void deltext(double e, message x) {
        Continue(e);
        if (phaseIs("passive")) {
          for (int i = 0; i < x.getLength(); i++) {
            if (messageOnPort(x, "result", i)) {
              job = x.getValOnPort("result", i);
              r_msg = (result_message) job;
              //System.out.println("Result Port로 Auctioneer로부터 결과 메시지 받음");
              if (r_msg.status == "progree") { //경매진행중, 판매요청불가
                phase = "passive";
                //System.out.println("결과 메시지의 status == progree, 경매진행중");
              }
              else if (r_msg.status == "end") { //경매종료, 판매요청가능
                count++;
                //System.out.println("결과 메시지의 status == end" + "\t" + (count - 1) +
                //                   " 번 째 상품 경매종료");
                if (count < 10) {
                  //System.out.println("=====================" + count +
                  //                   "번째 경매 대기=======================");
                  holdIn("active", int_arr_time);
                }
                else {
                  System.exit(0);
                }
    
              }
            }
          }
        }
      }
    
      public void deltint() {
        passivate();
        job = new entity("none");
      }
    
      public message out() {
    
    //System.out.println(name+" out count "+count);
    
        message m = new message();
        content con = makeContent("start",
                                  new start_message("START", inventory[count][0],
                                                    inventory[count][1]));
        m.add(con);
        /*System.out.println("start port로 Auctioneer에게 시작 메시지보냄: " + "\n" +
                           "================" + count +
                           "번째 경매 시작: " + "Inventory : " + inventory[count][0]
                           + "\t" + "Initial Price : " + inventory[count][1] +
                           "==============");*/
        return m;
      }
    
      public void showState() {
        super.showState();
    
      }
    
      public String getTooltipText() {
        return
            super.getTooltipText()
            + "\n" + " int_arr_time: " + int_arr_time
            + "\n" + " count: " + count;
      }
    
    }


    // Auctioneer.java
    // modifued by Aettie Ji
    // April 21st, 2009
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    import simView.*;
    import java.io.RandomAccessFile;
    
    public class Auctioneer
        extends ViewableAtomic {
      protected entity job;
    //protected double processing_time;
      double list[][];
      double sort[][];
      int count; //입찰카운트, 총 5회진행
      String max_bidder; //최고입찰자
      double max_price; //최고입찰가
    
    //경매기록 파일 작성
      RandomAccessFile out;
    
      start_message s_msg;
      bidding_message b_msg;
      int customer_num; //경매참여자수
      int case_num; //어떤 메시지 입력을 받는가 구별
      int check[]; //입찰자의 입찰여부 체크
      double temp1, temp2; //정렬 등을 위한 임시변수
      String status; //현재 상태를 받기위한 변수
    
      public Auctioneer() {
        this("Auctioneer", 20);
      }
    
      public Auctioneer(String name, int num) {
        super(name);
        customer_num = num;
        list = new double[customer_num][2];
        sort = new double[customer_num][2];
        check = new int[customer_num];
        for (int i = 0; i < customer_num; i++) {
          addInport("bidin" + i); //각 customer bidout과 연결
          list[i][0] = i;
          list[i][1] = 1;
          sort[i][0] = i;
          sort[i][1] = 1;
          check[i] = 0;
        }
        addInport("in"); //start message from supplier
        addOutport("out"); //result message to supplier
        //addOutport("priceout");
        addOutport("start");
        try {
          out = new RandomAccessFile("biddingHistory.txt", "rw");
          System.out.println(
              "****************************파일생성***************************");
        }
        catch (Exception e) {
          System.out.println("Can't open file " + e);
        }
      }
    
      public void initialize() {
        phase = "passive";
        sigma = INFINITY;
        job = new entity("job");
        max_bidder = "";
        max_price = 0;
        count = 0;
        case_num = 0;
        temp1 = 0;
        temp2 = 0;
        s_msg = new start_message("START", 0, 0);
        b_msg = new bidding_message("BID", 0, 0);
        super.initialize();
      }
    
      public void deltext(double e, message x) {
        Continue(e);
    
        if (phaseIs("passive")) {
          for (int i = 0; i < x.getLength(); i++) {
            if (messageOnPort(x, "in", i)) {
              job = x.getValOnPort("in", i);
              s_msg = (start_message) job;
              //System.out.println("In Port로 supplier로부터 시작 메시지 받음");
              try {
                out.writeBytes("Product Num : " + s_msg.product_num + "\t"
                               + "Initial Price : " + s_msg.initial_price + "\n");
              }
              catch (Exception ex) {
                System.out.println("Can't Write " + ex);
              }
              case_num = 1;
              holdIn("busy", 0);
              }
          }
          for (int j = 0; j < customer_num; j++) {
            for (int i = 0; i < x.getLength(); i++) {
              if (messageOnPort(x, "bidin" + j, i)) {
                job = x.getValOnPort("bidin" + j, i);
                b_msg = (bidding_message) job;
                //System.out.println("Bidin Port로 customer로부터 입찰 메시지 받음");
                list[j][0] = b_msg.customer_num;
                list[j][1] = b_msg.bidding_price;
                if (list[j][1] == 0) {
                  check[j] = 0;
                  //System.out.println("Customrt_" + j + "는 입찰하지 않았음");
                }
                else if (list[j][1] != 0) {
                  check[j] = 1;
                  case_num = 2;
                  //System.out.println("Customrt_" + j + "는 입찰 하였음");
                }
              }
            }
          }
          if (case_num == 2) {
            count++;
            //System.out.println(count + " 번째 입찰======================");
            for (int k = 0; k < customer_num; k++) {
              sort[k][0] = list[k][0];
              sort[k][1] = list[k][1];
            }
            //bubble sort
            for (int a = 0; a < customer_num - 1; a++) {
              for (int b = a + 1; b < customer_num; b++) {
                if (sort[a][1] > sort[b][1]) {
                  temp1 = sort[a][0];
                  sort[a][0] = sort[b][0];
                  sort[b][0] = temp1;
                  temp2 = sort[a][1];
                  sort[a][1] = sort[b][1];
                  sort[b][1] = temp2;
                  //System.out.println("Sorting");
                }
              }
            }
    
            max_bidder = "Customer " + sort[0][0];
            max_price = sort[0][1];
            //System.out.println("max_bidder :" + max_bidder + "\t" + "max_price :" +
            //                   max_price);
            try {
              out.writeBytes("----------Bidding count : " + count + "---------" +
                             "\n");
              for (int b = 0; b < customer_num; b++) {
                out.writeBytes("Customer :" + list[b][0] + "\t" + list[b][1] +
                               "\n"); //경매과정 list[][]출력
              }
              out.writeBytes("Max Bidder :" + max_bidder + "\t" + "Max Price :" +
                             max_price + "\n"); //누가 maxbidder인지 출력
            }
            catch (Exception ex) {
              System.out.println(ex);
            }
            holdIn("busy", 0);
          }
        }
      }
    
      public void deltint() {
        passivate();
        job = new entity("none");
      }
    
      public void deltcon(double e, message x) {
        deltint();
        deltext(0, x);
      }
    
      public message out() {
        message m = new message();
        if (phaseIs("busy")) {
          if (case_num == 1) {
            m.add(makeContent("start", s_msg));
            //System.out.println("Start Port로 customer에게 시작 메시지 보냄");
          }
          else if (case_num == 2) {
            if (count < 5) {
              int participant = 0;
              for (int a = 0; a < customer_num; a++) {
                participant += check[a];
              }
              //System.out.println(participant + " 명 입찰");
              if (participant >= 2) {
                status = "progree";
              }
              else {
                count = 0;
                status = "end";
              }
            }
            else if (count >= 5) {
              count = 0;
              status = "end";
            }
            m.add(makeContent("out",
                              new result_message("RESULT", status, max_bidder,
                                                 max_price)));
            //System.out.println("Out port로 Supplier, Customer에게 결과 메시지보냄: " + "\n" +
            //                   "상태 : " + status + "MaxBidder : " + max_bidder
            //                   + "\t" + "MaxPrice : " + max_price);
          }
        }
        return m;
      }
    
      public void showState() {
        super.showState();
    //    System.out.println("job: " + job.getName());
      }
    
      public String getTooltipText() {
        return
            super.getTooltipText()
            + "\n" + "job: " + job.getName();
      }
    }
    


    // Auction_Customer.java
    // modifued by Aettie Ji
    // April 21st, 2009
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    import simView.*;
    
    public class Auction_Customer
        extends ViewableAtomic { 
      protected entity job;
      int num;
      double bid_price; //입찰가
      double PE; //가격 탄력성
      double MBP; //최고입찰한도
      double real_MBP; //실제 최고입찰가
      double posted_price; //현재 시장가
      start_message s_mess;
      bidding_message b_mess;
      result_message r_mess;
    
      public Auction_Customer() {
    //this("Auction_Customer",20);
      }
    
      public Auction_Customer(String name, int n, double m, double p) {
        super(name);
        addInport("pricein"); //result_messge
        addOutport("bidout"); //bidding_message
        addInport("in"); //start_message
        num = n;
        MBP = m;
        PE = p;
      }
    
      public void initialize() {
        phase = "passive";
        sigma = INFINITY;
        job = new entity("job");
        s_mess = new start_message("START", 0, 0);
        b_mess = new bidding_message("BIDDING", 0, 0);
        r_mess = new result_message("RESULT", "end", "", 0);
        super.initialize();
      }
    
      public void deltext(double e, message x) {
        Continue(e);
    
        if (phaseIs("passive")) {
          for (int i = 0; i < x.getLength(); i++) {
            if (messageOnPort(x, "in", i)) {
              job = x.getValOnPort("in", i);
              s_mess = (start_message) job;
              //System.out.println("In Port로 Auctioneer로부터 start 메시지 받음");
              real_MBP = s_mess.initial_price * MBP; //실제입찰한도
              bid_price = s_mess.initial_price + (int) (Math.random() * PE); //첫번째 입찰가
              holdIn("busy", 0);
            }
          }
          for (int i = 0; i < x.getLength(); i++) {
            if (messageOnPort(x, "pricein", i)) {
              job = x.getValOnPort("pricein", i);
              r_mess = (result_message) job;
              //System.out.println("pricein Port로 Auctioneer로부터 result 메시지 받음");
              posted_price = r_mess.highest_price;
              if (r_mess.status == "progree") {
                if (posted_price < real_MBP) {
                  bid_price = posted_price + (int) (Math.random() * PE);
                }
                else {
                  bid_price = 0;
                }
              }
              else {
                bid_price = 0;
              }
              holdIn("busy", 0);
            }
          }
        }
      }
    
      public void deltint() {
        passivate();
        job = new entity("none");
      }
    
      public void deltcon(double e, message x) {
        deltint();
        deltext(0, x);
      }
    
      public message out() {
        message m = new message();
        if (phaseIs("busy")) {
          m.add(makeContent("bidout", new bidding_message("BIDDING", num, bid_price)));
        }
        //System.out.println("Bidout Port로 Auctioneer에게 bidding 메시지 보냄");
        return m;
      }
    
      public void showState() {
        super.showState();
    //    System.out.println("job: " + job.getName());
      }
    
      public String getTooltipText() {
        return
            super.getTooltipText()
            + "\n" + "job: " + job.getName();
      }
    }


    // start_message.java
    // modifued by Aettie Ji
    // April 21st, 2009
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class start_message
        extends entity {
      public double product_num; // 상품 번호
      public double initial_price; // 초기 가격
    
      public start_message(String name, double num, double ip) {
        super(name);
        product_num = num;
        initial_price = ip;
      }
    }


    // bidding_message.java
    // modifued by Aettie Ji
    // April 21st, 2009
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class bidding_message
        extends entity {
      public int customer_num; //입찰자정보
      public double bidding_price; //입찰가격
    
      public bidding_message(String name, int num, double bp) {
        super(name);
        customer_num = num;
        bidding_price = bp;
      }
    }


    // result_message.java
    // modifued by Aettie Ji
    // April 21st, 2009
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class result_message
        extends entity {
      public String status; // 경매진행상태
      public String highest_bidder; // 최고 입찰자
      public double highest_price; // 최고 가격
    
      public result_message(String name, String s, String hb, double hp) {
        super(name);
        status = s;
        highest_bidder = hb;
        highest_price = hp;
      }
    }



    저작자 표시 비영리 변경 금지
    Creative Commons License
    Creative Commons License
    이번 시간엔 Minimum Load First Scheduling Model을 맹글어보았다.
    말그대로, 지난 시간의 Round Robin Scheduling처럼 생성되는 job을 순서대로 processor에 한개씩 한개씩 보내는 것과는 달리
    5개의 프로세서 중 현재 가장 적은 Workload를 가진 processor에게 job을 주겠다는 뜻이다.

    그렇다면 Round Robin Scheduling에서 변경되어야 할 몇 가지를 살펴보면,

    1. Scheduler가 workload를 계산할 수 있도록 하기 위해 필요한 값을 입력받을 port와 이 필요값을 저장할 공간이 필요하다.
      • Scheduler의 in port는 Generator로 부터 job을 받을 1개의 port와,
      • 각 5개의 Processor로 부터 job이 solved되었다는 정보를 받을 5개의 port로 총 6개가 필요하다.
      • 다음과 같은 배열을 만든다.
        Processor Number Workload
         0  0
         1  0
         2  0
         3  0
         4  0
      • 해당 번호의 Processor로 job이 할당되면 Workload 1증가 (이 때 processor의 queue 크기인 10을 넘을 수 없다.)
      • 해당 번호의 Processor로부터 solved message를 받으면 Workload 1감소

    2. 가장 Workload가 적은 processor를 계산하는 부분이 필요하다.
      • Bubble Sort를 사용하는데, sorting방법은 어떤 것을 사용해도 관계없다.
      • 현재 상태에서 가장 workload가 적은 processor에 job을 할당한다.

    3. 모든 5개의 processor의 processing time이 같다면, workload를 계산하는 의미가 없다. (어차피 순서대로일 테니깐...) 그래서 각 processor의 processing time을 다르게 할당해준다.
      • Processor 0 = 10
      • Processor 1 = 15
      • Processor 2 = 20
      • Processor 3 = 15
      • Processor 4 = 25


    다이어그램은 요렇다.

    다음은 소스 코드...
    // mlfsm.java
    // modified by Aettie Ji
    // April, 7 2009
    
    package SimpArc;
    
    import java.awt.*;
    import simView.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class mlfsm
        extends ViewableDigraph {
      int processor_num = 5;
      int queue_size = 10;
      int processingT[]; // 프로세싱 타임을 저장할 배열
      int int_arr_time = 5;
      int observation_time = 1000;
    
      public mlfsm() {
        super("mlfsm");
        processingT = new int[processor_num]; //프로세싱 타임을 저장할 배열
        processingT[0] = 10;
        processingT[1] = 15;
        processingT[2] = 20;
        processingT[3] = 15;
        processingT[4] = 25;
    
        ViewableAtomic g = new genr("GENERATOR", int_arr_time);
        ViewableAtomic t = new transducer("TRANSDUCER", observation_time,
                                          processor_num);
        ViewableAtomic s = new schedulerM("SCHEDULER_M", processor_num);
    
        add(g);
        add(t);
        add(s);
        //coupling 추가
        for (int i = 0; i < processor_num; i++) {
          ViewableAtomic p = new processor("PROCESSOR" + i, i, processingT[i],
                                           queue_size); // 배열에 저장된 processing time을 각각 할당
          add(p);
          addCoupling(s, "out" + i, p, "in");
          addCoupling(p, "out1", t, "solved");
          addCoupling(p, "out1", s, "in" + i);
          addCoupling(p, "out2", t, "in" + i);
        }
    
        addInport("in");
        addInport("start");
        addInport("stop");
        addOutport("out");
        addOutport("result");
    
        addCoupling(this, "in", g, "in");
        addCoupling(this, "start", g, "start");
        addCoupling(this, "stop", g, "stop");
        addCoupling(g, "out", s, "in");
        addCoupling(g, "out", t, "ariv");
        addCoupling(t, "out", g, "stop");
        addCoupling(t, "out", this, "result");
    
    //    initialize();
        showState();
        /*
          preferredSize = new Dimension(484, 145);
          g.setPreferredLocation(new Point(13, 18));
          p.setPreferredLocation(new Point(195, 18));
          t.setPreferredLocation(new Point(193, 80));
         */
      }
    
      /**
       * Automatically generated by the SimView program.
       * Do not edit this manually, as such changes will get overwritten.
       */
      public void layoutForSimView() {
        preferredSize = new Dimension(985, 409);
        ( (ViewableComponent) withName("SCHEDULER")).setPreferredLocation(new Point(
            135, 22));
        ( (ViewableComponent) withName("GENERATOR")).setPreferredLocation(new Point(
            11, 171));
        ( (ViewableComponent) withName("PROCESSOR3")).setPreferredLocation(new
            Point(376, 246));
        ( (ViewableComponent) withName("PROCESSOR0")).setPreferredLocation(new
            Point(366, 7));
        ( (ViewableComponent) withName("PROCESSOR2")).setPreferredLocation(new
            Point(369, 181));
        ( (ViewableComponent) withName("TRANSDUCER")).setPreferredLocation(new
            Point(645, 147));
        ( (ViewableComponent) withName("PROCESSOR1")).setPreferredLocation(new
            Point(374, 92));
        ( (ViewableComponent) withName("PROCESSOR4")).setPreferredLocation(new
            Point(377, 313));
      }
    }
    

    // schedulerM.java
    // modified by Aettie Ji
    // April, 7 2009
    
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    import simView.*;
    
    public class schedulerM
        extends ViewableAtomic { //ViewableAtomic is used instead
      //of atomic due to its
      //graphics capability
      protected entity job;
      protected double processing_time;
      int processor_num; //프로세서 갯수
      int out_port_num; //작업 보낼 아웃 포트
      int workload_list[][]; //work load save
      int temp_list[][]; //list for sorting
    
      public schedulerM() {
        this("schedulerM", 20);
      }
    
      public schedulerM(String name, int num) {
        super(name);
        processor_num = num;
    
        addInport("in");
        for (int i = 0; i < processor_num; i++) {
          addInport("in" + i); //프로세서 갯수만큰 inport 생성
          addOutport("out" + i); //프로세서 갯수만큰 outport 생성
        }
        processing_time = 0;
      }
    
      public void initialize() {
        phase = "passive";
        sigma = INFINITY;
        job = new entity("job");
        out_port_num = 0;
        workload_list = new int[5][2];
        temp_list = new int[5][2];
        for (int i = 0; i < 5; i++) {
          workload_list[i][0] = i; //processor num
          workload_list[i][1] = 0; //processor workload
          temp_list[i][0] = i;
          temp_list[i][1] = 0;
        }
        super.initialize();
      }
    
      public void deltext(double e, message x) {
        Continue(e);
    
        if (phaseIs("passive")) {
          //이중 for문을 이용하여 각 프로세서와 연결된 포트로부터 메시지 수신
          for (int j = 0; j < processor_num; j++) {
            for (int i = 0; i < x.size(); i++) {
              if (messageOnPort(x, "in" + j, i)) {
                job = x.getValOnPort("in" + j, i); //in+j로 들어온 메세지를 val에 저장
                workload_list[j][1]--; //포트로부터 완료작업이 들어오면 해당 프로세서의 작업로드 1 감소
              }
            }
          }
    
          for (int i = 0; i < x.getLength(); i++) {
            if (messageOnPort(x, "in", i)) {
              job = x.getValOnPort("in", i);
              for (int k = 0; k < processor_num; k++) {
                temp_list[k][0] = workload_list[k][0]; //프로세서 번호 복사
                temp_list[k][1] = workload_list[k][1]; //workload 복사
                System.out.println("Processor " + k + " 의 workload :" +
                                   workload_list[k][1]);
              }
              int temp1 = 0; //temp variable 1
              int temp2 = 0; //temp variable 2
              //bubble sort
              for (int a = 0; a < processor_num - 1; a++) {
                for (int b = a + 1; b < processor_num; b++) {
                  if (temp_list[a][1] > temp_list[b][1]) {
                    temp1 = temp_list[a][0];
                    temp_list[a][0] = temp_list[b][0];
                    temp_list[b][0] = temp1;
                    temp2 = temp_list[a][1];
                    temp_list[a][1] = temp_list[b][1];
                    temp_list[b][1] = temp2;
                  }
                }
              }
              out_port_num = temp_list[0][0]; //작업 부하가 가장 작은 processor
              if (workload_list[out_port_num][1] < 10) {
                workload_list[out_port_num][1]++; //지금 할당받은 processor 작업부하 1 증가
              }
              holdIn("busy", processing_time);
            }
          }
        }
      }
    
      public void deltint() {
        passivate();
        job = new entity("none");
      }
    
      public void deltcon(double e, message x) {
        deltint();
        deltext(0, x);
      }
    
      public message out() {
        message m = new message();
        if (phaseIs("busy")) {
          m.add(makeContent("out" + out_port_num, job));
        }
        return m;
      }
    
      public void showState() {
        super.showState();
        System.out.println("job: " + job.getName());
      }
    
      public String getTooltipText() {
        return
            super.getTooltipText()
            + "\n" + "job: " + job.getName();
      }
    }
    


    이제 마지막으로 지난시간의 rrsm와 비교실험을 할텐데,
    조건을 같게 해주기 위해 위의 mlfsm과 같이 5개 processor의 processing time을 다르게 설정하였다.
    소스는 그 부분만 다르지만 참고를 위해 rrsm과 이 scheduler소스코드로 같이 올린다.
    (사실은 지난 번 포스트를 찾아가서 보기 귀찮다으...)
    Generator와 Processro, Transducer는 완전히 같은 것을 사용하기 때문에 생략...

    // rrsmCompare.java
    // modified by Aettie Ji
    // April, 7 2009
    
    package SimpArc;
    
    import java.awt.*;
    import simView.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class rrsmCompare
        extends ViewableDigraph {
      int processor_num = 5;
      int queue_size = 10;
      int processingT[]; //프로세싱 타임을 저장할 배열
      int int_arr_time = 5;
      int observation_time = 1000;
    
      public rrsmCompare() {
        super("rrsmCompare");
        processingT = new int[processor_num]; //프로세싱 타임을 저장할 배열
        processingT[0] = 10;
        processingT[1] = 15;
        processingT[2] = 20;
        processingT[3] = 15;
        processingT[4] = 25;
    
        ViewableAtomic g = new genr("GENERATOR", int_arr_time);
        ViewableAtomic t = new transducer("TRANSDUCER", observation_time, processor_num);
        ViewableAtomic s = new scheduler("SCHEDULER", processor_num);
    
        add(g);
        add(t);
        add(s);
        //coupling 추가
    
        for (int i = 0; i < processor_num; i++) {
          ViewableAtomic p = new processor("PROCESSOR" + i, i, processingT[i],
                                           queue_size); // 배열에 저장된 processing time을 각각 할당
          add(p); 
          addCoupling(s, "out" + i, p, "in");
          addCoupling(p, "out1", t, "solved");
          addCoupling(p, "out2", t, "in" + i);
    
        }
    
        addInport("in");
        addInport("start");
        addInport("stop");
        addOutport("out");
        addOutport("result");
    
        addCoupling(this, "in", g, "in");
        addCoupling(this, "start", g, "start");
        addCoupling(this, "stop", g, "stop");
        addCoupling(g, "out", s, "in");
        addCoupling(g, "out", t, "ariv");
        addCoupling(t, "out", g, "stop");
        addCoupling(t, "out", this, "result");
    
    //    initialize();
        showState();
        /*
         preferredSize = new Dimension(484, 145);
         g.setPreferredLocation(new Point(13, 18));
         p.setPreferredLocation(new Point(195, 18));
         t.setPreferredLocation(new Point(193, 80));
         */
      }
    
      /**
       * Automatically generated by the SimView program.
       * Do not edit this manually, as such changes will get overwritten.
       */
      public void layoutForSimView() {
        preferredSize = new Dimension(985, 409);
        ( (ViewableComponent) withName("GENERATOR")).setPreferredLocation(new Point(
            11, 171));
        ( (ViewableComponent) withName("PROCESSOR3")).setPreferredLocation(new
            Point(376, 246));
        ( (ViewableComponent) withName("PROCESSOR1")).setPreferredLocation(new
            Point(374, 92));
        ( (ViewableComponent) withName("PROCESSOR4")).setPreferredLocation(new
            Point(377, 313));
        ( (ViewableComponent) withName("PROCESSOR0")).setPreferredLocation(new
            Point(366, 7));
        ( (ViewableComponent) withName("TRANSDUCER")).setPreferredLocation(new
            Point(645, 147));
        ( (ViewableComponent) withName("PROCESSOR2")).setPreferredLocation(new
            Point(369, 181));
        ( (ViewableComponent) withName("SCHEDULER")).setPreferredLocation(new Point(
            133, 70));
      }
    }
    

    // scheduler.java
    // modified by Aettie Ji
    // April, 7 2009
    
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    import simView.*;
    
    public class scheduler
        extends ViewableAtomic { //ViewableAtomic is used instead
      //of atomic due to its
      //graphics capability
      protected entity job;
      protected double processing_time;
      int processor_num; //프로세서 갯수
      int out_port_num; //작업 보낼 아웃 포트
    
      public scheduler() {
        this("scheduler", 20);
      }
    
      public scheduler(String name, int num) {
        super(name);
        processor_num = num;
    
        addInport("in");
        for (int i = 0; i < processor_num; i++) { //프로세서 갯수만큰 아웃포트 생성
          addOutport("out" + i);
        }
        //which should cause only "continue"
        processing_time = 0;
      }
    
      public void initialize() {
        phase = "passive";
        sigma = INFINITY;
        job = new entity("job");
        out_port_num = 0;
        super.initialize();
      }
    
      public void deltext(double e, message x) {
        Continue(e);
    
        if (phaseIs("passive"))
          for (int i = 0; i < x.getLength(); i++)
            if (messageOnPort(x, "in", i)) {
              job = x.getValOnPort("in", i);
              holdIn("busy", processing_time);
            }
      }
    
      public void deltint() {
        passivate();
        job = new entity("none");
      }
    
      public void deltcon(double e, message x) {
        deltint();
        deltext(0, x);
      }
    
      public message out() {
        message m = new message();
        if (phaseIs("busy")) {
          m.add(makeContent("out" + out_port_num, job)); //out0~4까지 job 객체를 송신
        }
    //라운드 로빈 스케줄링
        out_port_num++; //out port가 5 이상이 되는 경우, 존재하지 않는 out port이므로 0으로
        if (out_port_num > (processor_num - 1))
    //if(out_port_num>=processor_num)
        {
          out_port_num = 0;
        }
        return m;
      }
    
      public void showState() {
        super.showState();
        System.out.println("job: " + job.getName());
      }
    
      public String getTooltipText() {
        return
            super.getTooltipText()
            + "\n" + "job: " + job.getName();
      }
    }
    


    실험은 int_arr_time을 1부터 5로 증가시키면서 두 개의 모델을 비교하는 것이다.
    observation time은 1000이다.
    Int_arr_time Job Loss Rate Throughput AVG_TA
    MLFSM RRSM MLFSM RRSM MLFSM RRSM
    1 0.625 0.622 0.319 0.319 137.66 137.57
    2 0.259 0.277 0.319 0.319 124.00 102.82
    3 0.0 0.075 0.317 0.285 32.93 56.33
    4 0.0 0.004 0.245 0.236 14.79 32.33
    5 0.0 0.0 0.196 0.195 13.70 16.92


    저작자 표시 비영리 변경 금지
    Creative Commons License
    Creative Commons License
    네 번째 시간에는 Round Robin Scheduling Model을 만들었다아...
    스케줄러를 만들고 이 녀석이 여러 개의 프로세서에 순차적으로 job을 보내주는 역할을 하는 거다.
    각 프로세서는 queue로 되어 있어서, scheduler로 부터 받은 job을 차곡차곡 넣어놓고 처리하다가
    queue 크기를 초과하게 되면 job loss가 발생한다.

    각 모델이 하는 일과 변수를 좀 더 자세히 설명한 것이다...
    1. Generator (Atomic Model)
      • Generates a job every int_arr_time and send it to Scheduler.
      • Variables : int_arr_time(int), job_count(int)
    2. Scheduler (Atomic Model)
      • Determines the order for job allocation and allocates jobs to Processors in regular sequence. (If there are 3 processors in the RRSM, the order is P1→ P2→ P3→ P1→ P2→ P3…)
      • Variables : number_of_processor(int), outport_num(int)
    3. Processor (Atomic Model)
      • Process jobs and send them to Transducer
      • Variables : queue_size(int), job_loss(int), queue_count(int), processing_time(int)
      ※ Notice that Processor has a queue (size =10) to store jobs temporarily when the jobs are inputted to the processor with the "Busy" state. If a new job is inputted when the queue is full (number of stored jobs ≥ 10), the job will be lost and job_loss increases by 1. The processor sends out a solved job and a job_loss message through the "out1" port and the "out2" port.
    4. Transducer (Atomic Model)
      • Calculates Job loss rate, Throughput, and Average turn around time
      • Variables : observation_time(int), total_jobLoss(int), jobLoss(int [number of processors])
      ※ Notice that you have to make a new function to calculate job loss rate (the number of lost jobs / the number of generated jobs). Functions for Throughput and Average turn around time are provided by transd.java. And, loss messages from processors are inputted to some input ports (in0~in n).

    우리가 만들어야 하는 파일은 다섯개이다.
    1. Make the rrsm.java, which is modified from the gpt.java file. Notice that the number of processors is 5. Please refer to the above figure for the composition of the round robin scheduling model
    2. Make the loss_message.java, which is modified from the job.java file. Loss_message includes the processor number and its job loss count.
    3. Make the scheduler.java, which is modified from the proc.java.
    4. Make the processor.java, which is modified from the procQ.java. But, the queue of processor has the fixed size of 10.
    5. Make the transducer.java, which is modified from the transd.java. Add a new function for the calculation of job loss rate to transducer.

    그럼 하나씩 맹글어 봐야지,

    사실 generator는 변한 게 없다...ㅋㅋㅋ
    // generatorRrsm.java
    // Round robin scheduler model
    // modified by Aettie Ji
    // April, 1. 2009
    package SimpArc;
    
    import simView.*;
    
    import java.lang.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class generatorRrsm extends ViewableAtomic{
    
    	protected double int_arr_time;
    	protected int count;
    
    	public generatorRrsm() {this("generator", 30);}
    
    	public generatorRrsm(String name,double Int_arr_time){
    		super(name);
    		addInport("in");
    		addOutport("out");
    		addInport("stop");
    		addInport("start");
    		int_arr_time = Int_arr_time ;
    	}
    
    	public void initialize(){
    		holdIn("active", int_arr_time);
    	//  phase = "passive";
    	//  sigma = INFINITY;
    		count = 0;
    		super.initialize();
    	}
    	public void  deltext(double e,message x)
    	{
    		Continue(e);
    		if(phaseIs("passive")){
    			for (int i=0; i< x.getLength();i++)
    				if (messageOnPort(x,"start",i))
    					holdIn("active",int_arr_time);
    		}
    		if(phaseIs("active")){
    			for (int i=0; i< x.getLength();i++)
    				if (messageOnPort(x,"stop",i))
    					phase = "finishing";
    		}
    	}
    	public void  deltint( )
    	{
    		if(phaseIs("active")){
    			count = count +1;
    			holdIn("active",int_arr_time);
    		}
    		else passivate();
    	}
    	public message  out( )
    	{
    		message  m = new message();
    		content con = makeContent("out", new entity("job" + count));
    		m.add(con);
    
    		return m;
    	}
    	public void showState(){
    		super.showState();
    		System.out.println("int_arr_t: " + int_arr_time);
    	}
    	public String getTooltipText(){
    		return
    		super.getTooltipText()
    			+"\n"+" int_arr_time: " + int_arr_time
    			+"\n"+" count: " + count;
    	}
    }

    generator에서 생성한 job을 processor에 순서대로 분배하는 일을 하는 scheduler에서는
    processor의 갯수만큼 outport를 만들어 줘야 하고,
    이 해당 outport에서 메시지가 out되는 부분에서 스케줄링 해준다.
    즉, out() method에서 해주게 되는데, 아주 간단하게 message를 하나 내보낼 때마다 outport number를 하나씩 증가시키고,
    이 숫자가 processor의 갯수를 넘어가면, outport number를 다시 0으로 셋팅하면 된다.
    그러면 job이 processor의 순서대로 전달되게 된다.
    // scheduler.java
    // Round robin scheduler model
    // modified by Aettie Ji
    // April, 1. 2009
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    import simView.*;
    
    public class scheduler extends ViewableAtomic{
        protected entity job;
        protected double processing_time;
        int processor_num; //프로세서 갯수
        int out_port_num; //작업 보낼 아웃 포트
    
    	public scheduler(){
    	this("scheduler",20);
    	}
    
    	public scheduler(String  name, int num){
    		super(name);
    		processor_num = num;
    		addInport("in");
    		for(int i = 0; i < processor_num; i++)//프로세서 갯수만큰 아웃포트 생성
    		{
    			addOutport("out"+i);
    		}
    		processing_time = 0;
    	}
    
    	public void initialize(){
    		phase = "passive";
    		sigma = INFINITY;
    		job = new entity("job");
    		out_port_num = 0; // out_port_num 초기화
    		super.initialize();
    	}
     
    	public void  deltext(double e,message   x)
    	{
    		Continue(e);
    		if (phaseIs("passive")){
    			for (int i=0; i< x.getLength();i++){
    				if (messageOnPort(x,"in",i))
    				{
    					job = x.getValOnPort("in",i);
    					holdIn("busy",processing_time);
    				}
    			}
    		}
    	}
    
    	public void  deltint( )
    	{
    		passivate();
    		job = new entity("none");
    	}
    
    	public void deltcon(double e,message x)
    	{
    		deltint();
    		deltext(0,x);
    	}
    
    	public message    out( )
    	{
    		message   m = new message();
    		if (phaseIs("busy")) {
    			m.add(makeContent("out"+out_port_num,job));//out0~4까지 job 객체를 송신
    		}
    		//라운드 로빈 스케줄링
    		out_port_num++;//out port가 4 이상이 되는 경우, 존재하지 않는 out port이므로 0으로
    		if(out_port_num>(processor_num-1)) // processor_num - 1
    		{
    			out_port_num = 0;
    		}
    		return m;
    	}
    
    	public void showState()
    	{
    		super.showState();
    		System.out.println("job: " + job.getName());
    	}
    
    	public String getTooltipText(){
    		return
    		super.getTooltipText()+"\n"+"job: " + job.getName();
    	}
    }

    각 processor가 하는 일은 in port로 들어온 job을 처리하고 만약 queue가 다 찼는데도 job이 들어오면
    이를 loss로 간주하고, loss 발생시마다 job_loss 변수를 증가시키고 이를 job loss message에 포함시켜 transducer에 전달한다.
    때문에 out port는 두 개가 되는데, out1은 solved job이, out2는 loss message가 나가는 port이다.
    // processor.java
    // Round robin scheduler model
    // modified by Aettie Ji
    // April, 1. 2009
    package SimpArc;
    
    import simView.*;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class processor extends proc{
    	protected Queue q;	
    	int pNum;//프로세서 번호	
    	int queue_size;//큐사이즈	
    	int job_loss;//작업손실갯수
    
    	public processor(String  name,int n,double  Processing_time, int qz){
    		super(name,Processing_time);
    		q = new Queue();		
    		pNum = n;//프로세서 번호
    		queue_size = qz;//큐 사이즈 입력
    		addOutport("out1");//아웃포트2개생성
    		addOutport("out2");
    	}
    
    	public processor(){
    		super("procQ",20);
    		initialize();
    	}
    
    	public void initialize(){
    		q = new Queue();
    		super.initialize();
    	}
     
    	public void  deltext(double e, message   x){
    		Continue(e);
    		if (phaseIs("passive")){
    			for (int i=0; i< x.size(); i++){
    				if (messageOnPort(x, "in", i)){
    					job = x.getValOnPort("in", i);
    					holdIn("busy", processing_time);
    					q.add(job);
    				}
    			}
    		    job = (entity)q.first();  // this makes sure the processed job is the one at
                      //the front
    		}	 
    		else if (phaseIs("busy")){
    			for (int i=0; i< x.size();i++){
    				if (messageOnPort(x, "in", i)){
    					entity jb = x.getValOnPort("in", i);
    					if (q.size() < queue_size){
    						q.add(jb);
    					}
    					else {
    						job_loss++; //작업손실 발생하면 더해준다.
    						//System.out.println("JOB LOSS COUNT: "+job_loss);
    					}
    				}
    			}
    		}
    	}
    
    	public void  deltint( ){
    		q.remove();
    		if(!q.isEmpty()){
    			job = (entity)q.first();
    			holdIn("busy", processing_time);
    		}
    		else passivate();
    	}
    
    	public message    out( ){
    		message   m = new message();
    		if (phaseIs("busy")) {
    			m.add(makeContent("out1",job));//완료작업 전달
    			//작업손실정보전달
    			m.add(makeContent("out2", new loss_message("message",getName(),job_loss, pNum)));
    		}
    		//System.out.println("JOB LOSS COUNT: "+job_loss);
    		return m;
    	}
    
    	public void showState(){
    		super.showState();
    		System.out.println("Queue length: " + q.size());
    	}
    
    	public String getTooltipText(){
    		return
    			super.getTooltipText()
    			+"\n"+"queue length: " + q.size()
    			+"\n"+"queue itself: " + q.toString();
    	}
    }

    processor에서 loss_message라는 객체를 생성하여 보내는 것을 볼 수 있는데
    loss_message객체는 간단하다..ㅋㅋ

    해당 processor의 이름, 번호, job loss count만을 포함할 수 있도록 만든다.
    // loss_message.java
    // Round robin scheduler model
    // modified by Aettie Ji
    // April, 1. 2009
    package SimpArc;
    
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class loss_message extends entity{
         public String process_name; 
         public int process_num; // processor number
         public int job_loss; // job_loss의 갯수 전달
    
    	public loss_message(String name){
    		super(name);
    	}
    
    	public loss_message(String name,String pName, int jl, int pNum){
    		super(name);
    		process_name = pName;
    		process_num = pNum;
    		job_loss = jl;
    	}
    }

    transducer는 여러가지 측정치를 계산해 주는데, turn around time(compute_TA())
    throughput(compute_Thru())을 계산해 주는 함수는 이미 구현되어 있고,
    여기에다가 job loss를 계산하는 compute_JobLoss() 함수를 만들어준다.
    transducer는 계산을 위해서 여러 개의 port로 값을 받는데,
    ariv port로는 generator에서 생성된 job 메시지를, solved port로는 processor로부터 처리된 job을 받게 된다.
    우리는 5개의 processor를 만들었으므로, 5개의 processor out port로 부터 각각 solved와 loss 메시지를 받아야 한다.

    processor의 out1 port는 처리된 job을 transducer의 solved로 보내고,
    out2 port는 transducer의 5개의 in port로 각각 loss메시지를 보낸다.
    job loss 저장을 위해서 배열을 만들어 모두 더한 값을 generator에서 생성된 전체 job 갯수로 나누면
    job loss rate을 계산할 수 있다.

    이전과 다르게 추가된 부분은, processor에 job이 남아있더라도, observation time이 되면 system이 종료되도록 했다.
    // transducer.java
    // Round robin scheduler model
    // modified by Aettie Ji
    // April, 1. 2009
    package SimpArc;
    
    import simView.*;
    
    import java.lang.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class transducer extends  ViewableAtomic{
    	protected Function  arrived, solved;
    	protected double clock,total_ta,observation_time;
    	int processor_num;
    	int loss[]; //각 프로세서의 작업손실 갯수 
    	loss_message message;
    
    	public transducer(String  name,double Observation_time, int num){
    		super(name);
    		processor_num = num;
    		for(int i = 0; i < processor_num; i++){
    			addInport("in"+i);
    		}
    		addOutport("out");
    		addInport("ariv");
    		addInport("solved");
      
    		arrived = new Function();
    		solved = new Function();
    		observation_time = Observation_time;
    		entity test = new entity("val");
    		addTestInput("ariv",test);
    		addTestInput("solved",test,10);
    	}
    
    	public transducer()
    	{
    		this("transd", 200,5);
    	}
    
    	public void initialize(){
    		phase = "active";
    		sigma = observation_time;
    		clock = 0;
    		total_ta = 0;
    		loss = new int[processor_num];
    		message = new loss_message("message");//객체 초기화
    		arrived = new Function();
    		solved = new Function();
    		for (int i=0; i < processor_num; i++){ //배열 초기화
    			loss[i] = 0;
    		}
    	}
    
    	public void showState(){
    		super.showState();
    		System.out.println("arrived: " + arrived.size());
    		System.out.println("solved: " + solved.size());
    		System.out.println("TA: "+compute_TA());
    		System.out.println("Thruput: "+compute_Thru());
    	}
    
    	public void  deltext(double e,message  x){
    		clock = clock + e;
    		Continue(e);
    		entity  val;
    		//이중 for문을 이용하여 각 포트별로 메시지 수신
    		for (int j = 0; j < processor_num; j++){
    			for (int i = 0; i < x.size(); i++) {
    				if (messageOnPort(x, "in"+j, i)) {
    					val = x.getValOnPort("in"+j, i);//in+j로 들어온 메세지를 val에 저장
    					message = (loss_message)val;//입력받은 객체를 loss_message타입으로 형변환
    					loss[j] = message.job_loss;//작업 손실정보저장
    					//System.out.println("JOB LOSS COUNT: "+message.job_loss);
    				}
    			}
    		}
    		for(int i=0; i< x.size();i++){
    			if(messageOnPort(x,"ariv",i)){
    				val = x.getValOnPort("ariv",i);
    				arrived.put(val.getName(),new doubleEnt(clock));
    			}
    			if(messageOnPort(x,"solved",i)){
    				val = x.getValOnPort("solved",i);
    				if(arrived.containsKey(val.getName())){
    					entity  ent = (entity)arrived.assoc(val.getName());
    					doubleEnt  num = (doubleEnt)ent;
    					double arrival_time = num.getv();
    					double turn_around_time = clock - arrival_time;
    					total_ta = total_ta + turn_around_time;
    					solved.put(val, new doubleEnt(clock));
    				}
    			}
    		}
    		show_state();
    	}
    
    	public void  deltint(){
    		clock = clock + sigma;
    		passivate();
    		show_state();
    	}
    
    	public  message    out( ){
    		message  m = new message();
    		content  con = makeContent("out",new entity("TA: "+compute_TA()));
    		m.add(con);
    		return m;
    	}
    
    	public double compute_JobLoss(){
    		int total_job_loss = 0;//총 작업 손실 갯수
    		double job_loss_rate = 0; //작업 손실률
    		for(int i=0; i < processor_num; i++){
    			total_job_loss += loss[i];
    			// System.out.println("LOSS[i]: " +loss[i]);
    		}
    		job_loss_rate = ((double)total_job_loss)/arrived.size();
    		// System.out.println("TOTAL JOB LOSS COUNT: " + total_job_loss);
    		// System.out.println("ARRIVED SIZE: " + arrived.size());
    		// System.out.println("JOB_LOSS_RATE: " + job_loss_rate);
    		return job_loss_rate;
    	}
    
    	public double compute_TA(){
    		double avg_ta_time = 0;
    		if(!solved.isEmpty())
    			avg_ta_time = ((double)total_ta)/solved.size();
    		return avg_ta_time;
    	}
    
    	public double compute_Thru(){
    		double thruput = 0;
    		if(clock > 0)
    			thruput = solved.size()/(double)clock;
    		return thruput;
    	}
    
    	public void  show_state(){
    		System.out.println("state of  "  +  name  +  ": " );
    		System.out.println("phase, sigma : "
    			  + phase  +  " "  +  sigma  +  " "   );
    		if (arrived != null && solved != null){
    			System.out.println(" jobs arrived :" );
    	//      arrived.print_all();;
    			System.out.println("total :"  +  arrived.size()  );
    			System.out.println("jobs solved :" );
    	//      solved.print_all();
    			System.out.println("total :"  +  solved.size()  );
    			System.out.println("AVG TA = "  +  compute_TA()   );
    			System.out.println("THRUPUT = "  +  compute_Thru()  );
    			System.out.println("JOB LOSS = "  +  compute_JobLoss()  );
    		}
    		if (clock == observation_time){
    				System.exit(0); //clock == observation_time 이면 종료
    		}
    	}
    
    	public String getTooltipText(){
    		String  s = "";
    		if (arrived != null && solved != null){
    			s = "\n"+"jobs arrived :"   +  arrived.size()
    				+"\n"+"jobs solved :"  +  solved.size()
    				+"\n" + "AVG TA = "  +  compute_TA()
    				+"\n" + "THRUPUT = "  +  compute_Thru();
    		}
    		return super.getTooltipText()+s;
    	}
    }
    

    마지막으로 Round Robin Scheduler Model을 만들어 준다.
    각 atomic model을 추가하고, processor만 5개를 만들어주며, 그에 맞는 port끼리 coupling해 준다.
    // rrsm.java
    // Round robin scheduler model
    // modified by Aettie Ji
    // April, 1. 2009
    
    package SimpArc;
    
    import java.awt.*;
    import simView.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class rrsm extends ViewableDigraph{
    	int processor_num = 5;
    	int queue_size = 10;
    
    	public rrsm(){
    		super("rrsm");
    
    	    ViewableAtomic g = new generatorRrsm("GENERATOR",20);
    	    ViewableAtomic t = new transducer("TRANSDUCER",1000, processor_num);
    		ViewableAtomic s = new scheduler("SCHEDULER", processor_num);
    
    		add(g);
    	    add(t);
    		add(s);
    
    		// processor 수를 5개로 하여 생성하고, 각 processor의 port와 적절한 port를 coupling
    		for (int i = 0; i < processor_num; i++){
    			ViewableAtomic p = new processor("PROCESSOR"+i,i,50, queue_size);
    			add(p);
    			addCoupling(s,"out"+i,p,"in");
    			addCoupling(p,"out1",t,"solved");
    			addCoupling(p,"out2",t,"in"+i);
    		}
    		// rrsm diagraph model에 port 추가
    		addInport("in");
    		addInport("start");
    		addInport("stop");
    		addOutport("out");
    		addOutport("result");
    		// rrsm diagraph model에 coupling 추가
    		addCoupling(this,"in",g,"in");
    		addCoupling(this,"start",g,"start");
    		addCoupling(this,"stop",g,"stop");
    		addCoupling(g,"out",s,"in");
    		addCoupling(g,"out",t,"ariv");
    		addCoupling(t,"out",g,"stop");
    		addCoupling(t,"out",this,"result");
    
    		showState();
    	}
        /**
         * Automatically generated by the SimView program.
         * Do not edit this manually, as such changes will get overwritten.
         */
        public void layoutForSimView()
        {
            preferredSize = new Dimension(985, 409);
            ((ViewableComponent)withName("GENERATOR")).setPreferredLocation(new Point(11, 171));
            ((ViewableComponent)withName("PROCESSOR3")).setPreferredLocation(new Point(376, 246));
            ((ViewableComponent)withName("PROCESSOR1")).setPreferredLocation(new Point(374, 92));
            ((ViewableComponent)withName("PROCESSOR4")).setPreferredLocation(new Point(377, 313));
            ((ViewableComponent)withName("PROCESSOR0")).setPreferredLocation(new Point(366, 7));
            ((ViewableComponent)withName("TRANSDUCER")).setPreferredLocation(new Point(645, 147));
            ((ViewableComponent)withName("PROCESSOR2")).setPreferredLocation(new Point(369, 181));
            ((ViewableComponent)withName("SCHEDULER")).setPreferredLocation(new Point(133, 70));
        }
    }
    


    헥헥...힘들다...
    마지막으로...실험...ㅜ_ㅜ
    generator의 int_arr_time을 5부터 20까지 5씩 증가시키고,
    processor의 processing time을 10에서 50까지 10씩 증가시키면서
    job loss, throughput, average turn around time을 비교한다.
    transducer의 abservation time은 1000이다.

    JOB LOSS
    Int_arr_time/Processing time 5 10 15 20
    10 0.0 0.0 0.0 0.0
    20 0.0 0.0 0.0 0.0
    30 0.0 0.0 0.0 0.0
    40 0.1507 0.0 0.0 0.0
    50 0.2516 0.0 0.0 0.0


    THROUGHPUT
    Int_arr_time/Processing time 5 10 15 20
    10 0.197 0.098 0.065 0.049
    20 0.195 0.097 0.065 0.048
    30 0.161 0.096 0.064 0.048
    40 0.12 0.095 0.063 0.047
    50 0.095 0.094 0.063 0.047


    AVERAGE TRUNAROUND TIME
    Int_arr_time/Processing time 5 10 15 20
    10 10.0 10.0 10.0 10.0
    20 20.0 20.0 20.0 20.0
    30 108.01 30.0 30.0 30.0
    40 212.5 40.0 40.0 40.0
    50 275.0 50.0 50.0 50.0



    저작자 표시 비영리 변경 금지
    Creative Commons License
    Creative Commons License
    벌써 4주나 강의가 진행되었고, 오늘 바로 그 4주째 강의의 실험을 해야 하기땜시
    내친 김에 모조리 포스팅 해버려야겠다.
    어차피 복습도 좀 필요하고 말야...

    세 번째 시간은 아주 간단한 걸 했다...
    (그치만 4주째는 완전 초토화였다는거...ㅜ_ㅜ)


    요 모델은 지난 포스팅에 익히 보았던 gpt 모델이지만, 한 가지 다른 점이 있다.
    세 개의 atomic model을 사용한 것이 아니라, EF라는 diagraph model을 사용한 것이다.
    요 EF는 generator와 transducer를 합쳐놓은 것이다.
    뭐 조금 단정한 느낌이 드나?
    generator와 transducer 간에 서로 전달되어야 하는 메시지가 많으니 합치는 것이 더 좋을지도...


    세 번째 시간에 할 일은...

    1. Make the gtp3.java, which is modified from the gpt.java file. The GPT3 model includes a digraph model and a queue processor. The diagraph model is called the EF model which consists of a generator and a transducer. The generator and the queue processor can be referred from figures below. Expect and draw the trajectory of the transducer. Compare the simulation result of the GPT3 model. Note that the queue processor has 30 processing time and the Transducer has 200 observation time, and the generation time of the generator is repeatedly changed (15↔30, initial generation time = 15).
    2. What is the total turn_arround_time?
    3. What is the average of turn_arround_time?
    4. What is the throughput?

    EF 모델을 사용한 gpt3을 만들고,
    generator의 시간은 15 <->30으로 교환되고,
    queue processor의 processing time은 30
    transducer의 observation time은 200이다.

    위 조건으로 만든 gpt3.java파일이다.
    /* gpt3.java */
    /* modified by Aettie Ji*/
    /* March, 23. 2009 */
    
    package SimpArc;
    
    import java.awt.*;
    import simView.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class gpt3 extends ViewableDigraph{
    
    public gpt3(){
        super("gpt3");
        
    	//Diagraph model EF, initiall int_ariv_t = 15, ovservation time = 200 
        ViewableDigraph e = new ef1("EF",15,200);
        //Atomic model Queue processor p, processing time = 30
    	ViewableAtomic p = new procQ("p",30); 
    
         add(p);
         add(e);
    
    	 //Coupling "out" port of procQ with "in" port of EF
         addCoupling(p,"out",e,"in"); 
    	 //Coupling "out" port of EF with "in" port of procQ
         addCoupling(e,"out",p,"in");
    
         showState();
    }
        /**
         * Automatically generated by the SimView program.
         * Do not edit this manually, as such changes will get overwritten.
         */
        public void layoutForSimView()
        {
            preferredSize = new Dimension(604, 292);
            ((ViewableComponent)withName("p")).setPreferredLocation(new Point(32, 103));
            ((ViewableComponent)withName("EF")).setPreferredLocation(new Point(245, 71));
        }
    }
    


    generator도 수정되어야 하는데, 방법은 지난번과 유사하며 변수 값만 바뀌었다.
    /* genr4.java */
    /* modified by Aettie Ji*/
    /* March, 23. 2009 */
    
    package SimpArc;
    
    import simView.*;
    
    import java.lang.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class genr4 extends ViewableAtomic{
    
      protected double int_arr_time;
      protected int count;
    
      public genr4() {this("genr4", 30);}
    
    public genr4(String name,double Int_arr_time){
       super(name);
       addInport("in");
       addOutport("out");
       addInport("stop");
       addInport("start");
       int_arr_time = Int_arr_time ;
    }
    
    public void initialize(){
       holdIn("active", int_arr_time);
    
         count = 0;
         super.initialize();
     }
    
    public void  deltext(double e,message x)
    {
    Continue(e);
    if(phaseIs("passive")){
       for (int i=0; i< x.getLength();i++)
          if (messageOnPort(x,"start",i))
             holdIn("active",int_arr_time);
    	}
     if(phaseIs("active")){
       for (int i=0; i< x.getLength();i++)
          if (messageOnPort(x,"stop",i))
             phase = "finishing";
    	}
    }
    
    public void  deltint( )
    {
    
    if(phaseIs("active")){
       count = count +1;
       holdIn("active",int_arr_time);
    }
    else passivate();
    }
    
    public message  out( )
    {
      //Generation time of the generator is repeatedly changed 
      //(15↔30, initial generation time = 15)
      if (int_arr_time==15)
      {
        int_arr_time = 30;
      }
      else
        int_arr_time = 15;
    
       message  m = new message();
       content con = makeContent("out",
                new entity("job" + count));
       m.add(con);
    
      return m;
    }
    
    public void showState(){
        super.showState();
        System.out.println("int_arr_t: " + int_arr_time);
    }
    
    public String getTooltipText(){
       return
       super.getTooltipText()
        +"\n"+" int_arr_time: " + int_arr_time
         +"\n"+" count: " + count;
      }
    }


    마지막으로 EF model
    /* ef1.java */
    /* modified by Aettie Ji*/
    /* March, 23. 2009 */
    
    package SimpArc;
    
    import simView.*;
    
    import java.awt.*;
    import java.io.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class ef1 extends ViewableDigraph{
    
    public ef1(){
        super("ef1");
        efConstruct(10,500);
    }
    
    public ef1(String nm,double int_arr_t,double observe_t){
        super(nm);
        efConstruct(int_arr_t,observe_t);
    }
    
    public void efConstruct(double int_arr_t,double observe_t){
    
        addInport("in");
        addOutport("out");
        addOutport("result");
    
    	//Using genr4("name", int_arr_t) for changing generation time repeatedly
        ViewableAtomic g = new genr4("generator",int_arr_t); // generator와
        ViewableAtomic t = new transd("transducer",observe_t); // transducer를 생성
    
         add(g); //추가
         add(t);
    
         initialize();
         // 각 port의 coupling
         addCoupling(g,"out",t,"ariv");
         addCoupling(this,"in",t,"solved");
         addCoupling(t,"out",g,"stop");
         addCoupling(this,"start",g,"start");
         addCoupling(this,"stop",g,"stop");
         addCoupling(g,"out",this,"out");
         addCoupling(t,"out",this,"result");
    
        preferredSize = new Dimension(279, 146);
        g.setPreferredLocation(new Point(6, 17));
        t.setPreferredLocation(new Point(-5, 81));
    }
        /**
         * Automatically generated by the SimView program.
         * Do not edit this manually, as such changes will get overwritten.
         */
        public void layoutForSimView()
        {
            preferredSize = new Dimension(289, 221);
            ((ViewableComponent)withName("transducer")).setPreferredLocation(new Point(-7, 140));
            ((ViewableComponent)withName("generator")).setPreferredLocation(new Point(4, 44));
        }
    }
    


    transducer의 trajectory이다.
    성능 관련 계산 값들이 포함되어 있으므로 확인하면 될듯...


    저작자 표시 비영리 변경 금지
    Creative Commons License
    Creative Commons License
    DEVS의 Introduction
    그냥 쭉 훑어보기만 했다는..ㅋㅋㅋ
    두 번째 시간에는 GPT diagraph model에 대해 살펴보았다.
    말 그대로 generator, processor, transducer 세 개의 atomic model이 모여 이루어진 기본적인 모델이다.

    각 atomic model간의 port 연결 관계 및 하는 일들을 살펴보자.

    GENERATOR

    External function : 
    	- if messageOnPort(“start”) then holdIn("active", int_arr_time);
    	- if messageOnPort(“stop”) then phase = “finishing”;
    Internal function : 
    	- count++;
    	- holdIn("active", int_arr_time);
    Output function : 
    	- “out” : “job”+count를 proc에 보냄

    외부 함수는 어떤 port로 메시지가 전달되는가에 따라 generator가 무슨 일을 하는지를 나타낸다.
    즉, start port로 메시지가 오면, holdIn()을 호출하는데, 이 메소드는 int_arr_time의 시간에 "active"라는 상태가 된다는 의미이다.
    stop port에 메시지가 들어오면 job을 생성하는 일을 중단한다.
    내부 함수는 generator내부에서 일어나는 일이다.
    발생시키는 job의 갯수를 세고, 특정 시간(int_arr_time) 간격으로 "active"상태가 되도록 한다.
    즉, 특정 시간 간격으로 job이 생성된다.
    output 함수는 내부적으로 발생한 job을 외부로 전달하는 역할을 하는데, generator에서는 job+count 메시지를 processor에 전달하게 된다.

    PROCESSOR

    External function : 
    	- if messageOnPort(“in”) then holdIn("busy", processing_time);
    Internal function : 
    	- passivate();
    Output function : 
    	- “out” : entity job

    마찬가지로, processor의 in port로 메시지가 들어오면, processing_time동안 busy상태가 된다.
    즉, job을 처리하는 시간이다.
    passivate()메소드는 현재 상태를 passive로 만든다.
    processor의 초기 상태는 passive로, 상태가 passive여야지만 외부로부터 in port로 메시지를 받아 처리할 수 있다.
    processing_time만큼 처리가 완료된 job은 out port를 통해 메시지로 내보내진다.

    TRANSDUCER

    External function : 
    	- clock = clock + e;
    	- if messageOnPort(“ariv”) then put(val.getName(), new doubleEnt(clock));
    	- if messageOnPort(“solved”) 
                 then arrival_time = num.getv();
                       turn_around_time = clock - arrival_time;
                        total_ta = total_ta + turn_around_time;
                       solved.put(val, new doubleEnt(clock)); 
    Internal function : 
    	- passivate();
    Output function : 
    	- “out” : avg_ta_time 를 genr에 보냄

    transducer는 turn around time과 throughput을 계산하는 일을 한다.
    때문에 generator에서 job이 발생되고, processor에서 job이 처리완료 되었을 때 나오는 메시지를
    ariv와 solved port를 통해 받고 그 시간을 계산한다.
    turn_around_time의 평균은 generator에게 다시 전달된다.


    아웅...이런 간단한 것도 설명하기 참 어렵군하...ㅜ_ㅜ
    노파심에 다시 한 번 적는 건...
    이 포스팅은 복습의 의미이기 때문에 틀린 정보가 들어있을지도 모른다는 것...
    뭐 별로 참고할 것도 없지만, 혹시 참고하다가 틀린 점이 있으면 지적해주시는 센수~^^*


    자, 그럼 두번째 시간에 해야 할 일은 무엇인고 하니...
    1. Make the gpt2.java, which is modified from the gpt.java file. In the GPT diagraph model, the GPT2 digraph model includes the generator, the processor with queue (procQ.java) and the transducer. Note that the Processor has 15 processing time and the Transducer has 150 observation time, and the generation time of the Generator is repeatedly changed (10↔20, initial generation time = 10). Expect and draw the trajectory of the Transducer. Compare with simulation results of the GPT digraph model.
    2. What is each average of TA (Turn Around time) of the GPT digraph model and the GPT2 digraph model? TA is the time required to solve a job (the processing time + the waiting time in queue)
    3. What is each throughput of the GPT digraph model and the GPT2 digraph model? Throughput is the number of solved jobs by the DEVS time.

    아...참 많은 일을 해야 하는구나...
    일단, 원래 gpt.java를 수정하는데, 일반 processor가 아닌 queue processor를 사용하고,
    generator는 10, 20으로 job발생 간격을 계속 바꾸라는 것이고,
    processor는 15 processing time을 갖으며,
    transducer는 150 초 동안 이것 저것 계산하다가, 그 시간이 되면 generator에게 결과와 함께
    이제 그만 job 생성을 멈추시오~라는 메시지를 날리는거다.
    일반 processor와 queue procesor의 성능을 turn around time과 throughput을 이용해 비교해보라고 하는데,
    이건 생략하고(제출안했기 땜에 정리하지 않았다능..ㅋㅋㅋ, 표시되는 출력결과에 나오기 때매 직업 확인해보면 될듯...)

    GPT model
    // gpt2.java
    // modified by Aettie Ji
    // March, 17. 2009
    
    package SimpArc;
    
    import java.awt.*;
    import simView.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class gpt2 extends ViewableDigraph{
    
    public gpt2(){
        super("gpt2");
    
        ViewableAtomic g = new genr3("g",10); // job 발생시간 변경을 위해 수정한 generator 사용
        ViewableAtomic p = new procQ("p",15); // queue processor 사용
        ViewableAtomic t = new transd("t",150); // transducer
    
         add(g);
         add(p);
         add(t);
    // diagraph model에 port 추가
        addInport("in");
        addInport("start");
        addInport("stop");
        addOutport("out");
        addOutport("result");
    // 각 port의 연결
         addCoupling(this,"in",g,"in");
         addCoupling(this,"start",g,"start");
         addCoupling(this,"stop",g,"stop");
         addCoupling(g,"out",p,"in");
         addCoupling(g,"out",t,"ariv");
         addCoupling(p,"out",t,"solved");
         addCoupling(t,"out",g,"stop");
         addCoupling(p,"out",this,"out");
         addCoupling(t,"out",this,"result");
    
         showState();
    }
        /**
         * Automatically generated by the SimView program.
         * Do not edit this manually, as such changes will get overwritten.
         */
        public void layoutForSimView()
        {
            preferredSize = new Dimension(816, 409);
            ((ViewableComponent)withName("p")).setPreferredLocation(new Point(322, 274));
            ((ViewableComponent)withName("g")).setPreferredLocation(new Point(235, 118));
            ((ViewableComponent)withName("t")).setPreferredLocation(new Point(485, 61));
        }
    }
    

    수정한 generator
    package SimpArc;
    
    import simView.*;
    
    import java.lang.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class genr3 extends ViewableAtomic{
    
      protected double int_arr_time;
      protected int count;
    
      public genr3() {this("genr3", 30);}
    
    public genr3(String name,double Int_arr_time){
       super(name);
       // generator의 port들
       addInport("in"); 
       addOutport("out");
       addInport("stop");
       addInport("start");
       int_arr_time = Int_arr_time ; // 초기 int_arr_time을 매개변수로 받음.
    }
    
    public void initialize(){
         holdIn("active", int_arr_time);
         count = 0;
         super.initialize();
     }
    
    public void  deltext(double e,message x)
    {
    	Continue(e);
    	if(phaseIs("passive")){ // passive일 때, start port로 입력이 있으면
    	  for (int i=0; i< x.getLength();i++)
    	    if (messageOnPort(x,"start",i))
    	      holdIn("active",int_arr_time); // active
    	}
    	if(phaseIs("active")){ // active 때, stop port로 입력이 있으면
    	  for (int i=0; i< x.getLength();i++)
    	   if (messageOnPort(x,"stop",i))
    	        phase = "finishing"; // 종료
    	}
    }
    
    public void  deltint( )
    {
    	if(phaseIs("active")){ // active 이면
    	   count = count +1; // job count 증가
    	   holdIn("active",int_arr_time); 
    	}
    	else passivate();
    }
    
    public message  out( )
    {
      if (int_arr_time==10) // int_arr_time을 10<->20으로 교환
      {
        int_arr_time = 20; 
      }
      else
        int_arr_time = 10;
    
      message  m = new message();
      content con = makeContent("out", new entity("job" + count));
      m.add(con);
      return m; // 메시지를 생성하여 리턴
    }
    
    public void showState(){
        super.showState();
        System.out.println("int_arr_t: " + int_arr_time);
    }
    
    public String getTooltipText(){
       return
       super.getTooltipText()
        +"\n"+" int_arr_time: " + int_arr_time
         +"\n"+" count: " + count;
      }
    
    }


    위와 같이 수정했을 때의 trajectory
    그림 그리기가 더 빡시더라...ㅜ_ㅜ


    저작자 표시 비영리 변경 금지
    Creative Commons License
    Creative Commons License
    이번 학기에 듣는 수업이다.
    대학원에서는 흔치 않은 1시간 수업에 2시간 실습이 잡혀있는 수업으로...
    소프트웨어의 수학적 모델링에 대해 배우고, DEVS를 이용해서 실습한다.

    코딩이 딸리는 나로서는 조금 부담스러운 과목이 아닐 수 없지만
    나중에 유용하게 쓰일 수도 있을 것 같고 나름 재미도 있다.

    자세한 내용은 위키를 참고 하시기 바라며 http://en.wikipedia.org/wiki/DEVS...^^

    내 포스팅의 목적은 늘 그렇듯이,
    나중에 잊을때를 대비한 자료 축적 이거나, 사진이 아까워서이다.
    그래서 뭔가 정보를 얻기 위해 여기를 찾아오신 분들께는 어쩌면 도움이 별로 안될지도 모른다.
    순수하게 내 위주로 되어있기 때문이랄까...ㅋㅋㅋ

    뭐 각설하고, 그리하여 매 시간 충실히 수행하고 있는 실습 과제를 조금 정리해보고자 한다.
    실습에 사용되는 DEVSJAVA의 코드는 http://www.acims.arizona.edu/SOFTWARE/software.shtml 여기서 다운 받을 수 있고,
    뭔가 라이센스 폼을 보내는 복잡한 과정이 있는 듯 하여 파일을 직접 올리지 않으려고 한다.
    (나는 교수님께서 제공하신 강의용을 사용하고 있는지라..ㅋㅋ)

    음...수업에서 JBuiler 5를 사용하기 때문에 그걸 썼다.
    (이클립스 써보려다 삽질하고 포기..ㅜ-ㅜ)


    우리는 이제 소프트웨어를 모델링 하는 걸 배울거다...차근차근..ㅋㅋㅋ
    일단 모델은 여러 Atomic model과 이 Atomic model 들이 여러 개 모여 만들어지는 Diagraph model로 이루어진다.
    GENERATOR는 당연히 JOB을 생성하고, PROCESSOR는 JOB을 실행해서 결과를 낸다.
    다음은 PROCESSOR의 pseudo-code이다.
    Primary States:
    Phase: busy
    Sigma: any positive number
    
    Parameters:
    Job-id: alpha-numeric (e.g. job-1)
    Processing-time: any positive number (e.g. 50)
    
    Input port: in
    Output port: out
    
    External Transition Function:
         when receive input on input port “in” 
              if phase is passive
              job = input
              hold_in “busy” for processing-time
         else if phase is busy    // busy processing job
    continue // ignore input else error Internal Transition Function: If phase is busy set phase to passive set sigma to Infinity Output Function: Send “job”+id to output port “out” // send input (i.e. job-id) to output port “out”

    이제 우리가 할 일은 이렇다.
    1. Make the gproc.java, which is modified from the gpt.java file. The gproc digraph model includes the generator and the normal processor. You must remove all references to the transducer “t”, which is not needed in this digraph model. Expect and draw the trajectory of the normal processor. Compare with simulation results of the gproc digraph model.
    2. Note that the generation time of a generator is changed from 20 to 30 if the number of jobs exceeds 5 and the normal processor has 50 processing time.

    요걸 하기 전에, 우리가 건드려봐야 할 파일들은 좀 보면,

    SimpArc아래에...

    파일 이름들을 보면 대충 건드려야 할 파일들을 알 수 있다.

    일단 문제에서 말한 대로 gpt.java파일을 참고하여, gproc.java파일을 생성한다.

    // gproc.java
    // modified by Aettie Ji 
    // March, 17. 2009 
    
    package SimpArc;
    
    import java.awt.*;
    import simView.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class gproc extends ViewableDigraph{
    public gproc(){
        super("gproc");
    
        ViewableAtomic g = new genr2("g",20); //GENERATOR with initial generation time 20
        ViewableAtomic p = new proc("p",50); //PROCESSOR with processing time 50
    
         add(g); //GENERATOR add
         add(p); //PROCESSOR add
    
         addInport("in"); //port add
         addInport("start");
         addInport("stop");
         addOutport("out");
    
         addCoupling(this,"in",g,"in"); //coupling each port
         addCoupling(this,"start",g,"start");
         addCoupling(this,"stop",g,"stop");
         addCoupling(g,"out",p,"in");
         addCoupling(p,"out",this,"out");
    
         showState();
        /*
        preferredSize = new Dimension(484, 145);
        g.setPreferredLocation(new Point(13, 18));
        p.setPreferredLocation(new Point(195, 18));
        t.setPreferredLocation(new Point(193, 80));
        */
    }
        /**
         * Automatically generated by the SimView program.
         * Do not edit this manually, as such changes will get overwritten.
         */
        public void layoutForSimView()
        {
            preferredSize = new Dimension(816, 409);
            ((ViewableComponent)withName("p")).setPreferredLocation(new Point(322, 274));
            ((ViewableComponent)withName("g")).setPreferredLocation(new Point(235, 118));
            ((ViewableComponent)withName("t")).setPreferredLocation(new Point(485, 61));
        }
    }

    특별히 수정한 것은 없고, gpt.java파일은 세 개의 atomic model인 generator, processor, transducer를 모은 diagraph model이므로
    transducer에 관련된 내용을 모두 제거했다. 각 모델이 가져야 하는 port에 대해서는 아직 잘 모르겠다...
    그건 좀 더 배우면...ㅋㅋㅋ
    일단은 defalut로 되어 있는 것임...
    또 한가지 수정 사항은, 예제의 genr.java 가 아닌 새로운 Generator를 만든 것인데...
    이것은 문제에서 나온대로 초기 job 생성 시간을 5개 생성이후에 변경해 주기 위해서이다.

    // genr2.java
    // modified by Aettie Ji 
    // March, 17. 2009 
    
    package SimpArc;
    
    import simView.*;
    
    import java.lang.*;
    import genDevs.modeling.*;
    import genDevs.simulation.*;
    import GenCol.*;
    
    public class genr2 extends ViewableAtomic{
    
      protected double int_arr_time;
      protected int count;
    
      public genr2() {this("genr2", 30);}
    
    public genr2(String name,double Int_arr_time){
       super(name);
       addInport("in");
       addOutport("out");
       addInport("stop");
       addInport("start");
       int_arr_time = Int_arr_time ; //set int_arr_time
    }
    
    public void initialize(){
       holdIn("active", int_arr_time);
        //  phase = "passive";
       //  sigma = INFINITY;
         count = 1;
         super.initialize();
     }
    
    public void  deltext(double e,message x)
    {
    Continue(e);
    if(phaseIs("passive")){
       for (int i=0; i< x.getLength();i++)
          if (messageOnPort(x,"start",i))
             holdIn("active",int_arr_time);
    }
     if(phaseIs("active"))
       for (int i=0; i< x.getLength();i++)
          if (messageOnPort(x,"stop",i))
             phase = "finishing";
    }
    
    public void  deltint( )
    {
    /*
    System.out.println(name+" deltint count "+count);
    System.out.println(name+" deltint int_arr_time "+int_arr_time);
    System.out.println(name+" deltint tL "+tL);
    System.out.println(name+" deltint tN "+tN);
    */
    
    if(phaseIs("active")){
       count = count +1; //발생된 job의 갯수 세기
       holdIn("active",int_arr_time);
    }
    else passivate();
    }
    
    public message  out( )
    {
       if (count >= 5) // Job이 5개 이상 발생되면, 
           {
             int_arr_time = 30; //int_arr_time을 30으로
           }
       message  m = new message();
       content con = makeContent("out",
                new entity("job" + count));
       m.add(con);
      return m;
    }
    
    public void showState(){
        super.showState();
        System.out.println("int_arr_t: " + int_arr_time);
    }
    
    public String getTooltipText(){
       return
       super.getTooltipText()
        +"\n"+" int_arr_time: " + int_arr_time
         +"\n"+" count: " + count;
      }
    }

    int_arr_time이 job의 발생 간격이며, 이는 out() method에서 제어한다.
    상당히 복잡하다..ㅜ_ㅜ
    요 녀석의 Trajectory는...
    이렇게 그려진다.

    실행화면도 하나 넣어볼까?
    160 time에 job7이 generator에서 발생하여 processor로 넘겨지는 화면이다.
    step을 누르면 각 이벤트 발생 시점마다의 화면을 볼 수 있다.

    각 method에 대한 설명은...역시 천천히 정리하도록 하겠다...
    (뭔가 많이 들은 것도 같고, 이미 3주나 수업이 진행되었는데도...잘 모르겠는...ㅜ_ㅜ)

    저작자 표시 비영리 변경 금지
    Creative Commons License
    Creative Commons License
    언젠가 블로깅 하면서 본 이 깔끔한 코드 정리 폼을 얼마나 찾아다녔는지...
    상단의 물음표 버튼만 누르면 될 것을...

    난 바보인가보다...

    소프트웨어 공학 수업 내용을 차례로 정리해 놓으려고 마음먹고 일단 이 폼부터 찾으러 다고 찾았다.

    오늘 늦게 오긴 했지만, 벌써 4시도 넘었고...ㅜ_ㅜ,
    한 달 정도 기운만 있고 정작 걸리지 않는 감기 몸살과
    충치는 왼쪽인데 정작 오른쪽이 쿡쿡 쑤여대는 치통과 투쟁중이다...ㅜㅜ

    그래도 오늘 마음먹은 건 다 해버려야 할텐데...
    (1+1 행사를 하는 Alice Qee따윈 얼릉 잊어버리고 말야..1300k에서, 그것도 오늘까지..ㅋㅋㅋ)

    일단 테스트 겸, 나중에 잊어버릴 때를 대비한 백업 겸 해서 설치 내용과 삽입 코드 정리..ㅋㅋㅋ

    다운 받는 곳은 여기 http://alexgorbatchev.com/wiki/SyntaxHighlighter:Download
    자세한 사용법은 여기 http://alexgorbatchev.com/wiki/SyntaxHighlighter:Usage

    압축을 풀고, Tistory ADMIN\스킨\HTML/CSS편집\파일업로드 를 클릭하여 필요한 파일을 업로드 하자.
    scripts/*
    styles/*
    이 폴더의 모든 파일을 업로드 하면 되는데...(다는 필요없고, 사실 사용할 언어에 대한 파일만 업로드하면 되지만...귀찮으니 다 한다.)
    Tistory ADMIN에서는 모두 images/폴더 및으로 업로드 되기 때문에 요걸 기억해두고...

    이제 skin.html 파일에 몇 줄을 추가한다. head 태그 안에다가 요렇게...
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    여기서도 마찬가지로 본인이 사용할 언어의 파일만 넣어주면 된다는 거...

    사용은 요렇게...
    <PRE class="brush: java">
    //이 안에다 뭔가 원하는 코드를 써주삼!!
    </PRE>
    

    사용 언어의 브러쉬 리스트는 요기 http://alexgorbatchev.com/wiki/SyntaxHighlighter:Brushes
    글을 작성할 때는 EDIT모드가 아닌 HTML모드로...
    자꾸만 삽입되는 </br> 태그 주의!!

    저작자 표시 비영리 변경 금지
    Creative Commons License
    Creative Commons License

    'HotStudy+-+ > ...*ETC*...' 카테고리의 다른 글

    [Advanced Software Engineering] Generator + Proccessor Model  (0) 2009/03/30
    SyntaxHighlighter  (0) 2009/03/30
    [Review] AI Seminar  (0) 2008/12/22
    뚭앙이의 설치형 블로그 도전기! -1-  (0) 2008/04/11
    2005년도에, 처음 석사 들어왔을때 연구실 선배들과 했던 AI 세미나 때 만들었던 자료다.
    발표해 본 경험도 없는데다, 내용도 너무 어려워서
    (같은 책으로 학부때 수업을 들었음에도 불구하고, 그게 조박사 수업이었던지라...)
    엄청 떨었던 기억이...피피티도 왜 이리 허접한지..ㅋㅋㅋ

    교재는 요거... "Artificial Intelligence: A Modern Approach" Stuart Russell and Peter Norvig

    지난 논문들과 자료들을 정리하다보니, 연구실 KM 밑바닥에 요런게 있어서 올려본다...
    너무 허접해서 누가 참고할 수 있을만한 내용도 아니지만 서도..ㅋㅋㅋ







    Creative Commons License
    Creative Commons License

    'HotStudy+-+ > ...*ETC*...' 카테고리의 다른 글

    SyntaxHighlighter  (0) 2009/03/30
    [Review] AI Seminar  (0) 2008/12/22
    뚭앙이의 설치형 블로그 도전기! -1-  (0) 2008/04/11
    [Survey] Survey of NeOn Project  (0) 2008/02/16

    요즘은 매우 바쁘다...

    할 일도 많고 나이도 많기 때문에 시간은 없는데 말이다.

    이러고 있다.


    "바보야, 그렇게 살지마. 니가 그렇게 사니까 나라가 망하는 거야."


    이건 예전부터 하고 싶었던 취미생활의 일환으로, 전문적인 지식 없이 그냥 한 번 재미있을 것 같다는 생각에 밑도 끝도 없이 덤벼보는 그런 거, 말이다.

    설치형 블로그를 내 컴에서 돌리는 걸 한 번 시도해보자.

    이것 저것 만지면서 웹 프로그래밍 공부를 좀 해볼까 하는 생각도 들고 말야.

    컴퓨터 공학 박사 과정이다. >_</

    하지만 컴퓨터 포비아이다.


    성공만 한다면 곧 거미줄 칠 것 같은 네이버 블로그에서 슈웅~하고 이사가는 거다.


    그럼 웹서버부터 설치해야...하고 보니까 얼마 전에 xp를 밀고, vista를 깔아버렸다.

    자, 검색, 검색...해보니...MySQL과 Apache를 vista에 설치하는데 이래저래 문제가 생긴다고들 하신다. _ㅡ_

    에잇, 몰랏!

    그냥 APM_Setup을 깔아보는거다...하다가 안되면 말고..(사실 어떤 분이 시도해 보았더니 괘안타더라고 말씀하신 포스트를 보고...)

    http://www.apmsetup.com/ 요기에 들어가서 APM_Setup 5를 다운받아 설치, 대부분 C 드라이브에 설치되는 기본 설정대로 설치하라고들 하신다.

    사용자 삽입 이미지


    설치를 마치고 체크되어 있는대로 종료하면, 이렇게 Apache와 MySQL 서버가 실행된다. vista의 권한 문제 때문인지 맨 처음 자동 실행이 한 번 종료되지만 다시 실행하면 별 문제가 일어나는 것 같지는 않다. 

    예전에도 패스워드 막 바꿨다가 접속이 안되고 어찌저찌 열받고, 지우고 다시 깔고...하는 짓들을 반복한 경험이 있기 때문에 이번 기회에 차근하게 정리를...

    http://www.apmsetup.com/ 사이트의 tutorial 부분을 참고 했다.

    함께 열리는 README 파일을 보면 패스워드에 관련된 내용이 기술되어 있다. 초기 설치시의 APM_Setup 관리페이지의 패스워드와 MySQL root 패스워드는 apmsetup, 또한 phpMyAdmin 에 로긴 하실 때에도 ID / PS 를 root / apmsetup 라고...

    관리자 패스워드는 바로 저 아래 환경설정 버튼을 눌러서 나오는 창의 APM_Setup 환경설정 메뉴탭에서 변경한다.


    http://localhost/로 접속하면 아래와 같는 화면이 뜬다.

    사용자 삽입 이미지



    위 쪽 메뉴에서 맨 오른쪽 phpMyAdmin을 클릭하면, README 파일에 나온대로 root/apmsetup을 아이디와 패스워드로 치고 접속한다.


    사용자 삽입 이미지


    여기서 암호 변경을 클릭하고 패스워드를 변경한 후("1234"로 변경), 수정 버튼을 클릭하면 접속이 종료된다. 그러나, 이전의 패스워드든 바뀐 패스워드든 어떤 것으로도 접속할 수가 없다. (다른 분들도 그러신 건지는 잘 모르겠지만...)

    이제 C:\APM_Setup\Server\phpMyAdmin 폴더를 찾아가자. config.inc.php 파일을 Editplus 같은 걸로 열어서, 다음 부분을 변경해준다.


    $cfg['Servers'][$i]['controluser']   = 'root';          // MySQL control user settings
                                                                            // (this user must have read-only
    $cfg['Servers'][$i]['controlpass']   = '1234';         // access to the "mysql/user"
                                                                            // and "mysql/db" tables).
                                                                            // The controluser is also
                                                                            // used for all relational
                                                                            // features (pmadb)


    저 패스워드 부분이 변경되지 않은 채 'apmsetup'으로 되어 있었는데, 앞서 변경한 대로'1234'로 변경하여 저장한다. 그 다음, APM_Setup Monitor의 환경설정에서 MySQL 환경설정 탭에서 MySQL root 패스워드를 똑같이 '1234'로 변경한다. 이제, 서버를 모두 껐다가 재시작해도 이 패스워드로 phpMyAdmin에 접속이 된다는...ㅋㅋㅋ



    사용자 삽입 이미지

    그러면, 이제 데이터 베이스를 만들자. 블로그를 설치했을 때 여러 테이블들이 들어갈 데이터 베이스를 생성하는데, 설치시에 default로 생성된 mysql 데이터베이스를 그냥 사용해도 될 듯하다. 그래도 한 번 생성해 볼까...? myphpMyAdmin으로 아이디와 패스워드를 치고 딱 들어가서,  새 데이터 베이스 만들기에 원하는 데이터베이스 이름을 딱 쳐준다.

    내 경우는 'blog_db' !!


    Creative Commons License
    Creative Commons License

    'HotStudy+-+ > ...*ETC*...' 카테고리의 다른 글

    SyntaxHighlighter  (0) 2009/03/30
    [Review] AI Seminar  (0) 2008/12/22
    뚭앙이의 설치형 블로그 도전기! -1-  (0) 2008/04/11
    [Survey] Survey of NeOn Project  (0) 2008/02/16
     IAR 프로젝트 사전 조사 명목의 온톨로지 툴에 대한 조사 발표

    Creative Commons License
    Creative Commons License

    'HotStudy+-+ > ...*ETC*...' 카테고리의 다른 글

    SyntaxHighlighter  (0) 2009/03/30
    [Review] AI Seminar  (0) 2008/12/22
    뚭앙이의 설치형 블로그 도전기! -1-  (0) 2008/04/11
    [Survey] Survey of NeOn Project  (0) 2008/02/16

    BLOG main image
    히히히...ㅡ_ㅡ by 뚜방꽁

    카테고리

    ALL--? (352)
    .On.tHe.EDgE. (92)
    HotStudy+-+ (64)
    CoolTHINGS!! (196)

    달력

    «   2012/05   »
        1 2 3 4 5
    6 7 8 9 10 11 12
    13 14 15 16 17 18 19
    20 21 22 23 24 25 26
    27 28 29 30 31    
    Total : 47,301
    Today : 25 Yesterday : 40