세계 모든 나라에서 반려동물은 버려지지만 우리나라처럼 임신, 육아를 핑계로 키우던 개, 고양이를 버리는 일이 당연시되는 나라는 없다.
임신과 함께 반려동물을 버리는 이유는 기형, 불임, 감염 등 다양한데 그렇다면 다른 나라 부모들은 자기 자식보다 개, 고양이가 더 소중할까?
이 책은 우리나라만의 특이한 사회 현상에 대한 분석이자 아기와 반려동물이 안전하고 평화롭게 공존하기 위한 실용 육아 지침서이다.
책은 사람들이 얼마나 잘못된 정보를 지식으로 알고 있는지에 대해 의학적인 근거를 대며 조목조목 따지고, 유독 한국에만 있는 현상을 문화, 사회적으로 분석하고 이에 대한 원인과 해법을 제시하는 것으로 구성되어 있다.
국내에 처음 소개되는 각종 해외 의학 논문과 정보를 참조해 우리가 알고 있는 각종 정보가 왜곡되었음을 알리고 이런 문화가 형성되는데 언론 등 각종 매스미디어가 얼마나 결정적인 역할을 했는지 밝히고 있다.
물론 이런 현상의 이면에는 귀여울 때 키웠다가 생활의 변화가 생기니 버리고 싶은 이기심이 작동해 말도 안 되는 주장도 무조건 믿고 싶어 하는 무책임한 사람들의 심리가 있음도 지적한다.
더불어 반려동물과 함께 행복하고 안전하게 임신, 출산, 육아를 할 수 있는 방법을 제시한다. 어느 시기까지 반려동물과 아기를 격리시키는 것이 좋은지, 안전사고를 막기 위해 어떤 교육이 필요한지, 임신 중에 반려동물과의 생활은 어떠해야 하는지 등에 대한 구체적 정보와 자세한 설명은 아기와 반려동물을 함께 키우고자 하는 사람들에게 실질적인 도움이 될 것이다.
① 반려동물과 아기가 함께하는 안전한 임신, 출산, 육아에 대한 의학적 조언
사람들이 막연히 잘못 알고 있는 아기와 반려동물 함께 키우기에 대한 오해를 의학적으로 풀고, 아기와 반려동물이 건강하게 함께 살 수 있는 구체적인 방법을 제시한다. 국내에 소개되지 않았던 다수의 해외 의학 논문과 정보, 각종 해외 의학협회에서 권하는 반려동물과 아기를 함께 잘 키우는 방법에 대해서도 소개한다.
② 임신, 육아와 반려동물의 상관관계에 관한 국내 첫 설문 조사
결혼 후에 키우던 반려동물을 버리라는 이야기를 들었다 91%, 키우는 반려동물을 없애라는 이야기를 산부인과, 소아과 의사에게 들었다 41.1%, 임신이 늦은 이유가 반려동물 때문이라는 이야기를 들었다 50% 등 그간 공식적으로 드러나지 않은 사실들을 한 눈에 확인할 수 있었다.
③ 매스미디어 반려동물 보도의 무책임한 확대재생산
대체로 반려동물 관련 보도는 흥미 위주인데 종종 근거 없는 보도로 사람들의 공포심을 유발시키기도 한다. 아직 성숙되지 못한 반려동물문화의 계몽에 대한 책임은 방기한 채 흥미와 선정성 위주의 반려동물 관련 보도는 임신과 함께 반려동물을 버리는 사회 현상에 대한 책임을 물을 때 자유롭지 못하다.
④ ‘애완’동물 수준에 머무르는 반려인 태도와 책임감의 문제
아직도 반려인의 의식은 높지 못하다. 여전히 개, 고양이는 밥 주고, 예뻐해 주면 되는 대상일 뿐 교육에 대한 인식이 부재하고, 타인과 함께 갈등 없이 살기위한 반려인의 매너조차 갖추고 있지 못하다. 이런 상황에서 문제가 발생했을 때 가장 손쉬운 방법은 문제의 원인을 동물에게 씌우고 없애는 것이다. 진짜 원인은 사람인데 말이다.
Call for Papers for a Special Issue of International Journal of Electronic Commerce on MINING SOCIAL MEDIA
GUEST EDITORS
Jose C. Cortizo, CTO, principal researcher on Social Media at Social Gaming Platform, professor at
Universidad Europea de Madrid. josecarlos.cortizo@wipley.com
Francisco M. Carrero, CEO, principal researcher on Recommender Systems at Social Gaming Platform,
professor at Universidad Europea de Madrid. francisco.carrero@wipley.com
Jose M. Gomez, Research Director at Optenet, jgomez@optenet.com
OVERVIEW
Recently, Forrester published a report, “The Future of the Social Web” where they sketched a timeline of the development of the Social Web, dividing its evolution in 5 eras. According to that report, the first era of the development of the Social Web started to explode the social relationships among users. Then, in the social functionality era, these social relationships resulted in the social functionality era where several websites started to add social functionalities in order to help users to interact with their peers. We are now in the era of Social Colonization, where technologies like Facebook Connect or Google Friend Connect have standardized social functionalities among websites and a vast majority of websites now include several social functionalities. Soon these federated identities will empower people to enter the era of social context with personalized and social content, and the development of tools for personalize social content will aim the development of the era of social commerce The primary goal of the proposed special issue of International Journal of Electronic Commerce is to foster research in the interplay between Social Media, Data Mining and Electronic Commerce, trying to reflect the actual developments on technologies that fit on the Social Context era.
SCOPE
The International Journal of Electronic Commerce is the #1-ranked journal on Electronic Commerce globally. This Special Issue will provide a significant opportunity for authors to publish important novel and original contributions in the area of Data Mining applied to Social Media. The guest editors seek papers and proposals that address various aspects of Mining Social Media, including recommender systems for social media, data mining algorithms designed to explode Social Networks, information management for Social Networks, etc.
RESEARCH QUESTIONS
We invite scholars and professionals from a broad range of disciplines to submit to this Special Issue. Papers
may encompass any or all of the following: foundational theoretical analyses, modelling, simulation, and
empirical studies. Authors may examine different aspects of mining social media in any of a variety of possible
contexts. Special topics of interest include, but are not limited to, the following:
A. Data Mining for Social Networks
• Novel Algorithms
• Association Rules
• Mining semi-structured data
• Classification and Ranking
• Clustering
• Text Mining
• Machine Learning
• Privacy Preserved Data Mining
• Statistical Methods
• Temporal and spatial data mining
• Parallel and Distributed Data Mining
• Interactive and Online Mining
• Data and Knowledge Visualization
• Multimedia mining (audio/video)
• Ensemble Methods
• Web Mining
• Graph Mining
• Link Mining
B. Information Management for Social Networks
• Recommender Systems
• Information Retrieval
• Sentiment Analysis
• Natural Language Processing
• Question Answering
• Semantic Processing
• Graph Analysis and Complex Networks
• Social Network Analysis
C. Possible applications
• Electronic Commerce
• E-Mail Spam Detection
• Blog/Social Networks Spam Detection
• Community Detection
• Users/content recommenders
• Trends discovery
• Blogs/Social Networks Community Dynamics
• User Reviews Ranking
• Blogs/Social Networks Contributions Summarization
• Abuse/Fraud Detection
• User Profile Modelling
• Event Detection and Tracking in Social Media
• Online Advertising
SUBMISSION GUIDELINES
Manuscripts submitted to the special issue should contain original material not published in nor submitted to other journals. Each manuscript has to have a cover page with the author information and another page with title and abstract but the author information omitted. The review process is double-blind and papers which do not meet publication quality standards will be rejected before the review process. Interested authors are required to submit extended abstracts of no more than two pages for their planned
submissions. This will give the editorial team an opportunity to determine if a given submission is appropriate or expedited handling and review.
Full papers should be sent via e-mail to Jose Carlos Cortizo <josecarlos.cortizo@wipley.com> in anonymized PDF Format, not including any author names or affiliations, and should not exceed 40 pages.
IMPORTANT DATES
Abstracts deadline 15 January 2010
Abstracts feedback 30 January 2010 Full paper submission 15 April 2010
Revisions notification 1 June 2010
Revised manuscripts 1 August 2010
Final decision 1 October 2010
GUEST EDITORS
Jose C. Cortizo,
CTO at Social Gaming Platform,
Professor at UEM, Spain josecarlos.cortizo@wipley.com
Tel: (+34) 912115616
Fax: (+34) 912115611
Francisco M. Carrero,
CEO at Social Gaming Platform,
Professor at UEM, Spain francisco.carrero@wipley.com
Tel: (+34) 912115616
Fax: (+34) 912115611
Jose M. Gomez
Research Director at Optenet
Spain jgomez@optenet.com
Tel: (+34) 902154604
Fax: (+34) 913575433
역시나 오랜만에 다시 연구를 좀 해봐야겠다고 생각해서 읽게 된 논문....
일년 남짓 이 쪽과 담 쌓고 살았으니, 다시 감을 좀 찾기 위해 선배오빠의 논문을 슬쩍 도와주기로 했다.
그래서 요즘 보고 있는건...
사용자가 컨텐츠에 단 태그가 시간이 지남에 따라 그 인기도랄까, 트렌드가 변하게 되는데
그걸 어떻게 하면 잘 측정해서 반영할까..에 대한 관련 연구를 읽고 있다.
읽었으니..기록, 기록, 기록..ㅋㅋㅋ
[Review] Trend Detection in Folksonomies
A. Hotho, R. J¨aschke, C. Schmitz, and G. Stumme
Y. Avrithis et al. (Eds.): SAMT 2006, LNCS 4306, pp. 56–70, 2006.
Springer-Verlag Berlin Heidelberg 2006
Abstract
Abstract. As the number of resources on the web exceeds by far the number of documents one can track, it becomes increasingly difficult to remain up to date on ones own areas of interest. The problem becomes more severe with the increasing fraction of multimedia data, from which it is difficult to extract some conceptual description of their contents. One way to overcome this problem are social bookmark tools, which are rapidly emerging on the web. In such systems, users are setting up lightweight
conceptual structures called folksonomies, and overcome thus the knowledge acquisition bottleneck. As more and more people participate in the effort, the use of a common vocabulary becomes more and more stable. We present an approach for discovering topic-specific trends within folksonomies. It is based on a differential adaptation of the PageRank algorithm to the triadic hypergraph structure of a folksonomy. The approach allows for any kind of data, as it does not rely on the internal structure of the documents. In particular, this allows to consider different data types in the same analysis step. We run experiments on a large-scale real-world snapshot of a social bookmarking system.
앞부분은 생략하고,
저자들은 PageRank를 기본으로 folksonomy내의 사용자, 리소스, 태그의 순위를 정한다. 결국 이 관계는 symmetric하기 때문에 사용자, 리소스, 태그의 어느 것에나 같은 방법을 적용할 수 있다.
PageRank를 사용하기 위해서 이들의 관계를 그래프로 나타내는데, tripartite 구조로 표현된다.
첫번째 그림이 일반적인 방향성 그래프의 형태라면, 두번째 그래프는 사용자가 어떤 리소스에 대해 어떤 태그를 사용하여 태깅하였는가를 나타내는 그래프이다.
이 그래프에서, PageRank와 같이 Random sufer model을 사용하는데,
w의 값이 weight, 즉, 해당 elememt의 rank값이 된다.
A는 row-stochastic version of adjacency matrix of the graph라고 되어있는데,
해당 엘리멘터에 대한 edge발생을 반영하기 위한 값으로 대충 이해하고 있다. (정확한 계산을 하려면 나중에 더 찾아봐야겠지만...)
여기서 중요한 건 p와 d의 값인데, p는 preference를 의미하고, d는 이 preference가 식에 얼마나 영향을 미칠것인가를 결정하게 된다.
이 p값을 이용하여, 저자들은 topic-specific한 rank를 결정할 수 있다고 주장하고 있다.
||w||=||p||를 유지하면서, d가 1보다 작을때(논문에서는 0.85)의 값에서 d가 1일때(특정한 preference가 없을때)의 값을 빼서 최종 weight값을 구한다.
실험에서는 메인 토픽 키워에 50%의 p값을 주고, 나머지 관련 태그에 나머지 p값이 그 관련정도에 따라 분포시켜 분석하고 있다.
다음은 내가 더 관심을 가지고 있는 부분인, 각 엘리먼트의 인기도 변화의 측정 부분이다.
t는 시간 단위, n은 해당 시간의 전체 엘리먼트의 사이즈, r은 해당 시간의 해당 엘리먼트의 랭킹이다.
(이 논문에서는 항상 사용자, 태그, 리소스에 대해서 각각 분석하고, 각 요소에 같은 식을 적용한다.)
수식의 의미는, 상위 90%의 엘리먼트가 80%로 순위가 올라가는 것은, 0.09%에 있는 엘리먼트가 0.08
% 위치로 올라가는 것보다 3배가 쉽다...는 의미로 계산된다. 이렇게 시간 t0 - > t1동안 각 엘리먼트의 순위 변화를 통해 트렌드를 계산한다.
이 논문에서는 이러한 값을 계산해서 추천에 이용한 것이 아니라, del.icio.us. 데이터를 이용하여 1년동안의 사용자, 태그, 리소스의 추이를 분석했다. 마지막으로 다른 논문의 Interestingness라는 트렌드 측정 방법과 비교하여, 상대적으로 long-term의 트렌드 분석에 본인들의 방법이 유리하다고 말하고 있다. (비교한 방법은 TF/IDF방식을 사용하고 있다....)
흑...역시 정리하는 건 너무 오래 걸린다...
그래도 나중에 다 피가 되고 살이 된다고 생각하고 열심히 하자!!!
우
리 헌법 1조는 국민주권을 천명하고 있다. 이러한 국민주권을 구체적으로 실현하기 위해 기본권이 보장되어야 함은 불문가지다.
하지만 이명박 정부는 갖은 편법과 권력의 오남용을 통해 기본권을 제한하고 있다. 이는 주권이 국민에게 있다는 공화국의 정신 즉,
민주주의에 대한 중대한 침해행위라고 평가하지 않을 수 없다.
특히 표현의 자유, 집회의 자유는 이명박정부가 들어선 이후 가장 심각하게 침해되고 있는 기본권 영역이다. 표현의 자유가 실존의 개인이라면 누구나 가져야 하는 양심의 자유에 바탕한다면, 집회의 자유는 그런 자유로운 양심에 바탕해서 그 개인이 집단으로서 정치에 참여하고, 사회에 참여할 수 있는 민주주의적 표현형태라고 할 수 있다. 이명박 정부는 이 양자를 모두 옥죄고 있다.
하나, 정부의 언론장악 음모를 비판한다. 언
론관계법을 통한 합법을 가장한 언론장악 시도는 지금 이순간에도 벌어지고 있다. 낙하산 인사를 통한 언론의 친정부화 시도는
MBC와 YTN 노조의 파업사태를 불러일으켰고, KBS의 인사이동 이후 KBS에 대한 비판적인 여론을 불러왔다. 이 일련의
행위는 정치언론을 부활시키고, 국민을 길들이기 위한 수단으로 언론을 전락시키려는 시도로 평가하지 않을 수 없다.
둘, "개인의 명예를 훼손한다." 라는 미명 하에 그 자신 국민이자 시민인 네티즌이 정당하게 행사해야 하는 마땅한 표현의 자유까지 억누르고 있다. 개인의 인격권은 존중되어야 하지만 이를 핑계로 정당한 표현의 자유가 제한되어선 안된다. 이명박 정부 하의 검찰은 듣도 보도 못한 모호한 법률규정을 근거로 정부정책을 비판하는 네티즌을 구속하는 유례 없는 만행을 저지른 바 있다(미네르바 사건).
이는 정당한 정치적 의사표현를 위축시키고, 네티즌이 스스로를 검열하는 자기 검열의 내면화를 유도하고 있다. 반면, 정부 정책에
반하는 공적 인물이나 유명인의 경우엔 공소사실이나 사생활까지 무책임하게 드러내는 등 차별적인 법 집행을 자행하고 있다. 이는
노무현 대통령의 서거라는 국가적인 비극을 불러온 큰 원인으로 작용하기도 했다.
셋, "불법 시위로 변질될 우려가 있다." 라는 실현되지 않은 자의적 추정만으로 평화로운 집회를 원천봉쇄하는 일이 빈번해지고 있다. 심
지어 노무현 대통령 서거 첫날에는 대한문 앞 조문객을 경찰벽으로 막는 반인륜적인 행위도 서슴지 않았다. 그 어느 민주국가가
국민들이 모여 자유롭게 이야기하는 것을 두려워하는가? 그 어느 민주경찰이 촛불을 든 아이를 무등태운 시민에게 촛불을 들고선
출입할 수 없다고 막아서는가? 이명박 정부는 이런 일련의 행위를 통해 스스로 민주 정부임을 포기하고 있다.
넷, 국민들은 정말 끈질긴 인내로 참아왔다.
지난 해 광화문을 가득 채운 촛불의 바다 앞에서 이명박 대통령은 스스로 반성한다고 말했다. 하지만 그 실천은 명박산성으로
표현되었다. 이제 더 이상 말로만 소통을 외치고, 말로만 반성을 외치는 때는 지났다. 구체적인 행동으로 국민과 소통하겠다는
의지를 보여줘야 한다. 하지만 그런 모습은 여전히 발견되지 않는다. 이에 국민들의 인내심은 한계에 다다르고 있다.
우리가 이명박 정부에 원하는 것은 대단한 것이 아니다. 우리는 상식을 원하고, 민주주의를 원하고, 표현의 자유를 원한다. 그리고 자유롭게 모여서 자신의 정치적인 입장을 개진할 수 있는 '열린 광장'을 원한다. 이
것이 왜 실현되지도 않은 자의적 우려에 의해 원천봉쇄되어야 하는가? 이러고도 이명박 정부는 민주주의 공화국의 정부임을
자임하는가? 과연 이명박 정부가 원하는 것은 박정희와 전두환, 노태우로 이어졌던 그 권위주의 정부인가? 우리는 되묻지 않을 수
없다.
시간을 거꾸로 돌리는 이명박 정부의 시계를 이대로 둘 수 없다.
더 이상 침묵하는 것은 4.19 혁명과 5.18 광주민주화항쟁, 그리고 6.10 대항쟁의 역사를 되돌리려는 반역사를 묵인하고,
추인하겠다는 것에 다름 아니다. 무수히 많은 학생과 시민들이 흘린 그 피의 가치를 그저 지워버리겠다는 걸 인정하는 것이고, 피와
땀으로 성취한 대한민국의 자랑스런 민주주의를 포기하겠다는 것이다. 이에 우리 블로거는 시민의 일원으로서 작은 목소리나마 현
시국에 보태지 않을 수 없었다. 우리 블로거들은 현 정부의 오만을 성토하며, 대한민국 민주주의의 발전과 대한민국 국민의 인간답게
살 권리를 위하여 이명박 정부와 여당에 다음과 같이 요구한다.
하나.일체의 언론장악 시도를 즉각 중단하라. 언론 관계법은 전면적으로 재검토되어야 한다. 하나. 표현의 자유를 보장하라. 특히 온라인 계엄령이라고 할 수 있는 지난 4월 국회 통과된 저작권법은 전향적으로 재개정되어야 한다. 하나. 집회의 자유를 폭넓게 보장하라. 원천봉쇄의 주술을 당장 거두라. 하나. 이명박 대통령은 비판적인 국민의 목소리에 경청하고, 자신의 실정을 반성하고, 사과하라. 그리고 작금의 총체적인 문제에 대한 납득 가능한 합리적인 해법을 제시하라.
* 위 글은 2009.6.11.오전 8:49.에 3차 추고한 글입니다.
* 이 글은 트위터를 중심으로 뜻을 함께한 블로거들이 의견을 모은 시국선언문 기초안을
바탕으로 임의 편집한 글입니다. 아래 링크로 표시된 블로거 시국선언문을 기초로 재편집이 가능하고, 그 초안을 그대로
복사/배포하는 것도 물론 가능합니다. 같은 취지로 제 편집본을 복사/편집/배포하는 것 역시 전적으로 자유입니다. 이 글은
저작권을 일절 주장하지 않습니다. 동료 블로거 여러분의 많은 참여를 당부드립니다.
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 POWER5는 dual core processor로 각 코어가 두 개의 Thread를 실행한다. Thread는 GCT(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 IPC와 execution time을 향상시키기 위해 POWER5의 priority가 어떻게 사용되는지를 보이는 어플리케이션 case study를 제공한다.
2.The POWER5 Processor
2.1 Dynamic HW resource balancing
POWER5는 HW dynamic resource balancing을 제공하는데, Thread가 L2 cache의 threshold에 도달하거나, TLB miss이거나, 너무 많은 reorder buffer entry를 사용했을 때, unbalanced한 리소스의 사용이 있다고 판단하여 blocking한다.
- Stall: congestion이 해결될 때까지 offending thread의 instruction decode를 멈춘다.
- Flush: congestion이 해결될 때까지, dispatch를 기다리고 있는 offending thread의 모든 instruction을 flush하고, 이 Thread가 더 이상 추가적인 instruction을 decode하지 않도록 한다.
2.2 SW-controlled priorities
이 SW-controlled priority는 decode stage에서 HW에 의해 수행되는데, 일반적으로, 높은 우선 순위는 더 높은 수의 decode cycle을 Thread에 할당한다. primary thread(PThread)와 secondary thread(SThread)가 있다고 하고, 각각 PrioP, PrioS의 우선 순위를 가지고 POWER5의 두 코어 중 하나에서 동작한다고 하자.
…..(1)
R은 PThread와 SThread의 우선 순위의 차이인, PrioP - PrioS를 사용해서 계산된다. 더 높은 우선 순위를 갖는 Thread는 R-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-benchmark는 Integer, Floating point, Memory와 Branch, 네 그룹으로 나뉘어 진다. integer group은 latency가 짧은 cpu_int와 latency가 긴 lng_chain_cpuint를 갖는다. memory group에서는 ldint_l2는 모든 load가 항상 L2 데이터 캐시에 hitting되고, ldint_mem은 메모리에 hitting된다. ldint_l2는 ldint_mem보다 높은 IPC를 갖는다. Branch 그룹에서는 br_hit과 br_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은 두 개의 PThread와 SThread의 우선 순위가 (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
그림 2는 positive 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_cpuint나 cpu_fp와 같은 thread는 높은 우선 순위로부터 얻는 이득이 적다. ldint_l2와 ldint_mem과 같은 memory-bound benchmark는 다른 memory-bound thread와 함께 작동할 때 prioritization mechanism의 이익을 얻어, ldint_l2의 성능은 240%, ldint_mem의 성능은 70%까지 향상되었다. 반면, cpu_int나 ldint_l1과 같은 높은 IPC의 thread는 추가적인 하드웨어 리소스로부터 이익을 얻을 수 있는 것과 같이 prioritization에 매우 민감했다. 그러므로, prioritization은 보통 total throughput이나 성능을 향상시킨다.
이 결과는 memory-bound benchmark가 유사한 요구조건의 다른 벤치마크와 경쟁할 때, POWER5 prioritization mechanism에 의한 영향을 받는다는 것을 보여준다. 그들은 순수한 cpu-bound benchmark보다는 덜 민감하며, memory-bound benchmark와 co-schedule 되었을 때만 증가된 우선 순위에 대한 이득을 얻는다. 때문에 memory-bound benchmark는 다른 memory-bound benchmark와 스케줄 될 때가 아니면 prioritization되지 않아야 한다.
추가적으로, +2의 우선순위의 차이는 상대적인 포화점을 나타내며, 거의 모든 벤치마크가 자신의 성능의 95%이상에 다다랐다는 것을 의미한다. memory-bound benchmark는 가장 큰 성능의 증가가 +2에서 +3에서 나타나므로 이 규칙의 예외이다.
4.2 Effect of Negative Priorities
그림 3은 ldint_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이 두 배 이상 증가할 수 있는 몇 가지 경우를 보여준다. 이는 우선 순위가 낮은 Thread의 slowdown의 비용에서 얻는 것으로 특히 lng_chain_cpuint와 같이 낮은 우선 순위의 Thread가 낮은 IPC를 가진 경우이다.이러한 경우는 낮은 IPC의 Thread가 이 slowdown을 커버할 수 있고, 총 throughput이 중점적인 목표일 때 사용될 수 있다.
Cpu-bound benchmark의 성능이 그 우선 순위와 함께 향상되는데 반해 memory-bound benchmark는 상대적으로 일정하게 유지된다. 일반적으로 높은 IPC의 Thread의 우선 순위를 증가시켰을 때 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의 효과에 대한 그래프이다. 대부분의 영향을 받는 thread는 ldint_l1, cpu_int, ldint_l2로 memory-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_fp와 lng_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 resource를 thread 간에 balancing하는 것을 더 효과적으로 하는 것을 허용하는 SW/HW c-design의 폭넓은 활용으로 가는 길을 열어 주었다.
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책과 각종 인터넷 자료를 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)
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)))
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.
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)
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의 매핑 방법은 디바이스의 타입에 따라 다르다.
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)
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를 갖는다.
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요청이 이루어진다.
모든 개별 캐시에 대한 state와 트랜지션 다이어그램은 같다. 디렉토리 스테이트의 갱신과 리퀘스트를 만족시키는 메시지를 보낸다. 메모리 블럭의 모든 카피를 트랙킹한다. sharing set과 sharer의 갱신 액션도 지시한다.
Example directory protocol
디렉토리로 보내지는 메시지는 , 디렉토리의 갱신, 리퀘스트를 만족시키기 위한 메시지, 두 액션에 의해 발생한다.
Uncached상태의 블럭: 메모리의 카피가 현재 값, 이 블럭에 대해 가능한 리퀘스트는
읽기미스: 요청하는 프로세서가 메모리로부터 데이터를 받는다. 요청자는 sharing mode만 될 수 있다. 블럭의 상태는 shared가 된다.
쓰기미스: 요청하는 프로세서는 값을 받고, sharing mode가 된다. 블럭은 vaild한 카피만을 캐시한 것을 알리는 exclusive상태가 되고, 공유자는 소유자의 아이덴티티를 표시한다.
shared상태의 블럭: 메모리의 값이 최신상태이다.
읽기미스: 요청하는 프로세서는 요청한 데이터를 메모리로부터 받고, 공유자 셋에 추가된다.
쓰기미스: 요청하는 프로세서는 값을 받는다. 공유자 셋에 있는 모든 프로세서는 invalidate메시지를 받는다. 공유자 셋은 이 요청 프로세서의 아이덴티티를 포함한다. 블럭의 상태는 exclusive가 된다.
exclusive상태의 블럭: 블럭의 현재 값은 공유자 셋에 의해 표시되고 있는 프로세서(소유자)의 캐시에 유지되어 있다.
읽기미스: 소유자는 데이터 페치 메시지를 받는다. 이 메시지는 소유자의 캐시에 있는 블럭의 상태를 shared 상태로 전환되도록 하고, 소유자가 데이터를 메모리에 쓰여질 수 있도록 디렉토리로 보내도록 하는 역할을 한다. 요청 프로세서의 아이덴티티는 공유자 셋에 추가되고 소유 프로세서의 아이덴티티도 여전히 포함되어 있다.
data WB: 소유 프로세서는 블럭을 교체하고, 이 블럭은 WB된다. 이 WB은 메모리 카피를 최신으로 만들고(홈 디렉토리가 소유자가 된다) 블럭은 이제 uncached가 된다. 공유자 셋은 비워진다.
쓰기미스: 블럭은 새로운 소유자를 갖는다. 이전의 소유자에게 메시지가 보내지는데, 캐시는 블럭을 invalidate하고 , 새로운 소유자가 될 요청 프로세서로부터 온 값을 디렉토리에 보낸다. 공유자는 새로운 소유자의 아이덴티티를 셋하고 블럭은 exclusive상태를 유지한다.
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?
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)
SMP
MP motivation
uniprocessor 발달의 둔화는 ILP의 효과를 떨어뜨리고, power의 소비에 관련된 관심이 증가하면서 멀티 프로세서의 연구가 주요 이슈로 등장, 이러한 트렌드를 더욱 뒷받침하는 몇가지 요인을 살펴보면,
data-intensive application의 증가
server와 server performance에 대한 관심 증가
데스크탑의 성능에 대한 중요성 감소 (이미 충분히 쓸만하게 빨라서?)
어떻게 멀티프로세서를 효율적으로 사용할 것인가에 대한 이해 증진, 특히 자연적인 Tread-level prarllelism이 큰 서버 환경에서
중앙메모리와 각 프로세서를 연결하는 버스사용, large cache를 사용함으로서 버스의 BW를 충분히 줄일 수 있다. 프로세서 여러개를 하나의 board로 묶거나, 다중 버스를 사용하거나, interleaved memory를 사용하기도 한다.
각 프로세서의 private data와 프로세서 간의 shared data를 모두 캐싱하는데, 공유데이터의 latency, memory BW, interconnection BW를 모두 줄일 수 있으나, cache coherence문제가 발생할 수 있다.
Cache coherence problem
프로세서는 이번트 3 이후에는 다른 값을 보게 된다. write back cache에서 언제 어느 값이 쓰여지고 어떤 캐시가 플러쉬되는가는 happenstance에 의존하므로, 메인 메모리를 접근하는 프로세서는 변경되지 않은 값을 보게 될 수 있고 매우 빈번하다.
아래와 같은 경우, 일관성을 보장할 수 없으나, 서로 다른 프로세서로부터 같은 위치를 접근하도록 요청되었을 때 그 순서를 지키도록 한다. 그러나 같은 위치에대해서만 지켜지므로 coherence가 충분하지 않다.
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: 블럭이 데이터를 가지고 있지 않는 상태
읽기 미스는 모든 캐시가 버스를 스누핑하게 한다.
블럭을 클린하게 하는 쓰기는 미스로 간주된다.
Example
A1과 A2는 같은 캐시블럭에 맵핑되어 있고 초기 캐시상태는 invalid이다.
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)
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)
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(참고)
Vector programming
Vector length register에 작동 범위 할당 가능, [vector length register max -1], 메모리의 r1(base)부터 시작하여, r2(stride)의 간격으로 LD, SD한다.
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 수를 의미)
일반적으로 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를 사용할 때
Vector Unit Structure
FU에 맞게 레지스터를 분배하고, 연속된 데이터가 서로 다른 레지스터에 저장될 수 있도록 한다.
FU가 충분하다면 각각 독립된 레지스터 셋을 갖기 때문에 intruction 수행시 동시에 여러 레지스터를 read 할 수 있다.
Vector Memory-memory vs. Vector register machine
VMM instruction은 모든 벡터 피연산자를 메모리에 유지한다. 즉, 메모리에 직접 연산하는데 비해, 벡터 레지스커 머신은 벡터 레지스터로 로드하는 연산을 한다.
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
벡터 레지스터에 로드나 이전 연산이 완료되지 않아도, 일부 데이터만 가져다가 연산에 사용
체이닝을 사용하지 않는다면 연관있는 이전 인스트럭션의 마지막 엘리먼트가 종료될때까지 다음 인스트럭션을 수행할 수 없다. 체이닝을 할 경우, 이전 인스트럭션의 결과가 나오자 마자 연관된 다음 인스트럭션 수행 가능
Vector startup
다중 lane을 사용하여 성능을 증가시킨다고 해도, startup latency를 줄일 수 없다. 그러나, 이전 벡터 인스트럭션의 완료와 다른 벡터 인스트럭션의 시작이 오버랩되도록 하여 startup overhead를 줄일 수 있는데, 가장 심플한 방법은 두 개의 벡터 인스트럭션이 서로 다른 벡터 레지스터를 접근하도록 하는 것이다.
일부 벡터 머신에서는 첫번째 벡터 인스트럭션의 마지막 엘리먼트와 다음 인스트럭션의 첫번째 엘리먼트 사이에 dead time을 두어 제어 로직을 간단히 한다.
따라서, vector startup penalty는 FU latency, 즉 파이프라인을 지나는 시간 + dead time(recovery time), 즉 파이프라인에서 다른 벡터 인스트럭션이 시작되기 전까지의 시간이다.
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에 들어가지 않도록 하는 구현
Compress/Expand operations
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
: MFLOPS rate on an infinite-length vector
벡터 길이가 무한하다면 빛의 속도, 실제로는 무한한 벡터 길이는 없고, startup penalty가 존재한다.
: 의 절반에 가까워지기위해 필요한 벡터의 길이, startup의 영향을 측정
: 스칼라 모드보다 벡터 모드가 빨라지기 위한 벡터 길이,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 클럭 사이클이 걸린다.
미디어를 지배하는 자가 의식을 지배하고 대중의 의식을 지배하는 자가 권력을 통제하게 된다.
정말 무섭다. MB정부...
그래, 뭐...
나는 "수구 세력이 잃어버렸던 10년"동안 20대를 보낸 사람이라서, 자유를 통제하는 것에 익숙치 않고,
그랬기 때문에 오히려 사회 문제에 대한 날카로운 시각을 가질 수 없었던 것이었을런지 모른다.
지금 내 또래의 젊은 사람들이 다 마찬가지일 거다.
그나마 그 안일하고 게으른 시각을 보완해 줄 수 있었던 것이 일부 깨어있는 지식인들이었는데...
우리 나라는 어디로 가고 있는 걸까...
노 대통령님 생전에 한나라당이 정권을 잡을까봐 무섭다는 말씀이
이런 사태를 염려해서였을까...라는 생각이 든다.
수업을 좀 빠져서...중간중간에 스킵된 내용을 때우느라고 조금 힘들었다능...
사실 출력 부분이 두 번씩 출력되는 것이...출력문의 위치를 잘못 넣은 것 같긴 하지만
대충 얼추 비슷하게 나오는 것 같아서 그냥 두었다는...
(사실 치명적인 실수가 숨어 있을지 모르지만, 귀찮으니 그냥 넘어간다...지금보니 변수의 철자도 맞지 않는 것이..쿨럭...)
지난 번의 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
Auctioneer 가 Supplier와 Customer에게 경매가 시작됐음을 알린다.
Supplier와 Customer는 최초 입찰 가격을 Auctioneer에게 보낸다.
Auctioneer는 양측의 입찰 가격을 비교하여 가격 균형이 이루어 졌는지 확인해 본 후 가격 균형이 이루어 진 경우 입찰을 종료 하고 아니면 추가 입찰을 통보 한다.
Supplier와 Customer는 입찰 가격을 재 조정하여 다시 입찰한다.
SBP = Previous Bidding Price of Supplier – Rand(Price Elasticity of Supplier)
CBP = Previous Bidding Price of Customer + Rand(Price Elasticity of Customer)
3번을 진행한다.
입찰이 종료 되면 종료 메시지와 함께 양측에 입찰 가격을 보낸다.
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사이의 가격에서 랜덤하게 설정)
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 이하 의 값 중 랜덤하게 선택
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;
}
}
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)
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와 일으킬 수 있는 충돌이 성능을 저하시키지 않을 것을 보장해야 한다.
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)
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 인스트럭션을 분리
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단계
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한 것을 표시
normal data bus: data + destination
common data bus: data + source ;64bit of dada and 4bit FU address, 여러 FU가 있기때문에 어디서 왔는지 표시, FU와 맞는 것이 있으면 write(produces results), broadcast
LD inst issue
load buffer; busy와 address
register status; F6의 값이 load1에 의해 나올 것임을 기술
LD inst issue
load 2 busy, 목적주소 저장
F2의 값이 load2에 의해 만들어짐을 저장
multiple load 가능
Multd issue되고 , RS의 FU에 기록,
R(F4)는 source operand
load2에 의해서 나올 F2의 값을 기다려야 함을 기록,
F0은 Multi1에 의해 생성됨을 기록
RS에서는 레지스터의 이름이 저장되지 않는다.
LD는 1 cycle이 소비된다고 가정했으므로 load1 complete
SUBD issue, load1 해제
load1이 완료되어 register write( F6)되어 값을 얻었으므로, M(A1)은 바로 read할 수 있다.
load2는 아직 결정되지 않았으므로 기록함
load2가 완료되어 F2값이 결정되었고, 이제 MULTD와 SUB의 실행이 가능해진다.
SUB는 2 cycle이 실행에 소비되므로 time = 2, MULTD는 10 cycle이 소비되므로 time =10
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한 것을 표시
실제 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)를 사용한다.
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)
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의 반복이 독립적이라는 것을 발견하여, 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를 읽는 단계로 나눈다.
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)
Memory Hierarchy
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)
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을 사용한다.
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)
교재의 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씩 증가
파이프라이닝은 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
하드웨어가 오버랩된 실행 인스트럭션의 모든 가능한 컴비네이션을 동시에 제공할 수 있는 것이 아닐 경우 발생
가장 흔히 functional unit이 fully pipelining되지 않았을 때 발생, 해당 unit을 사용하는 instruction의 경우 클락사이클 당 한번의 비율로 진행을 멈춰야한다.
또 다른 경우는, 리소스가 파이프라인에서 실행되어야 하는 모든 인스트럭션의 컴비네이션을 허용할 만큼 복제되지 않을 때 발생한다. 예를 들어 프로세서가 한 개의 레지스터가 한 개의 write port만 가지는데 한 클락에서 동시에 두개의 write를 시도할 경우 등이다. 필요한 유닛이 사용 가능해질 때까지 stall된다.
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를 해결하기 위해, 인스트럭션을 위한 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 연산 스테이지에 준다는 얘기다.
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을 채운다.
(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등을 활용하여 구현할 수 있다.
이 내용을 참고하시기 전에...
시험 공부용으로 급하게 정리한 후 절대 다시 수정하지 않았기 때문에 내용이 매우 조잡하며,
책을 보고 정리하긴 했지만 정확한지 확신할 수 없는 부분이 많음...
(그닥 참고할 사람도 많지는 않겠지만) 대충 훑어보는 정도로 참고해주셈~ ^^
(언제나 그렇듯이 언젠가는 한 번 볼 일이 있을지 모른다는 의미의 "개인적인 정리" 개념임.)
중간고사는 안 보실 줄 알았는데,
기말고사 걱정 하면서..이 과목 빡쎄니 이제 슬슬 정리도 하고 준비해야겠는데...하고 있었는데
이게 왠걸...중간고사라니...ㅜ_ㅜ
(울어버릴겁니다..ㅜ_ㅜ)
뭐부터 손대야 할지 전혀 모르겠지만,
어차피 복습 개념으로 천천히 정리를 시작하려고 마음먹었던 거니까
차분한 마음으로 시작해보자...
우선 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
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에 의해 다음 수행 인스트럭션이 결정되는 것 간의 딜레이에 의해 발생된다.
the principle of locality
어떤 특정 시간대에 프로그램이 접근하는 주소공간은 상대적으로 작다. 즉, 프로그램이 수행될 때 한 번 사용한 데이터를 또 사용하거나(temporal locality: loop, reuse) 그 주변의 데이터를 곧 접근할 가능성이 많다(spatial locality: straight line code, array access).
focus on the common case
common sense를 따른다. 예를 들어 intruction fetch나 decode unit은 multiplier보다 더 빈번히 사용되므로 먼저 optimize한다. 더욱 빈번한 케이스는 종종 더 간단하고, 빠른 시간에 수행된다. 예를 들어, 덧셈에서 오버플로우가 발생하는 경우보다 발생하지 않는 경우가 더 일반적이므로, 발생하지 않는 쪽은 optimize한다. 만약 오버플로우 때문에 딜레이가 발생하더라도, 빈번한 케이스를 optimize했으므로 전체적인 성능은 향상될 수 있다. 컴퓨터의 특정 부분을 향상시킴으로서 얻을 수 있는 퍼포먼스 향상은 Amdahl's law로 계산한다.
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를 사용한 부분의 실행시간이다.
예제를 풀어보자공...
-- 새로운 프로세서는 원래 프로세서보다 computation이10배 빠르다. 원래 프로세서의 computation이 40%, IO가 60%라면 overall speedup은?
시스템이 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
일반적으로 실제 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가 그만큼 좋은 것, 참조 컴퓨터의 값은 없어지므로 아무 컴퓨터나 선택해도 된다.
산술평균 대신 기하평균 사용
기하 평균이 벤치마크 suite의 모든 프로그램의 성능을 모두 반영할 수 없으므로, 평균을 벗어나는 특이한 값들을 표현하기 위해 기하표준편차를 사용한다.
fallacy: 벤치마크가 유명해지면, 벤치마크에 해당하는 프로그램만 성능을 좋도록 만든다. 주기적으로 변경되어야 한다.
disk의 rated MTTF는 1200000 hour, 140년에 해당하지만 디스크의 생명은 5년이다. 온도변화나 진동등이 없는 안정된 환경에서만 얻을 수 있는 값이다.
pitfall: 반드시 평균적인 프로그램의 성능이 골고루 좋아야 되는것은 아니다. 어떤 부분은 fail하더라도 전체 성능에 큰 영향을 미치지 않을 수 있다. power supply등의 경우
사실 내가 작성한 건 아니다...ㅜ_ㅜ
뭐 수업시간에 따라서 코딩하긴 했지만 장기적으로 찾아온 슬럼프때문에 숙제고 수업이고 잠시 손을 놓았었는데
다행히 같이 수업을 듣는 명덕이가 다 작성해줬다..ㅋㅋㅋ
내가 한 건 아니지만 그래도 기록의 의미로 또 포스팅...
(사실 이번 주엔 발표를 해야되는데...난 어떻게 되고 있는지 전혀 모른다는...미안 명덕 ㅡ,.ㅜ)
MinneTAC Model은 TAC SCM 이라 불리는 공급망 관리를 위한 경쟁 에이전트들 중 하나이며 경매 모델과 같은 경제 모델 중 하나이다.
수요자(고객)는 서로 다른 성향을 지니며 각각의 성향에 따라 상품 공급을 요청하고 공급자(에이전트)는 서로 다른 전략을 가지고 중개자를 통해 수요자와의 거래를 성립한다.
MinneTAC Model은 4개의 부분(Customer, Broker, Bank, Supplier)으로 구성된다.
3개의 Customer와 1개의 Broker와 Bank, 2개의 Supplier로 구성된다.
PROCESS
각각의 Customer는 자신의 제안 가격(Offer Price) 범위와 제안 요구량(Offer Demand) 범위 내에서 랜덤하게 상품 공급 요청(RFQ)에 대한 가격과 요구량을 제시하고 해당 거래의 만기일(Due Date)을 함께 제시한다.
Broker는 Customer로부터 받은 RFQ를 기반으로 각각의 Supplier의 전략(MaxEProfit, DemandDriven)에 적합한 Customer와 거래를 중개한다. 동시에 요청된 세 개의 상품 공급 요청(RFQ) 중 기대이익(Profit)이 가장 높은 것은 MaxEProfit 전략을 가진 SupplierA와 거래하고 주문량(Demand)이 가장 많은 것은 DemandDriven 전략을 가진 SupplierB와 거래하도록 한다.
상품 공급 요청(RFQ)을 받은 각각의 Supplier는 거래 만기일(Due Date) 동안 상품을 생산하여 Customer에게 만들어진 상품을 제공한다고 가정하고 해당 거래가 종료된 후 Broker로부터 다음 거래를 할당 받는다.
각각의 Supplier는 하나의 거래가 종료될 때마다 해당 거래에 대한 순이익(margin)을 얻게 되는데 이것은 Bank에 누적하여 저장한다.
각각의 Customer는 일정한 주기로 상품 공급을 요청하고 Broker는 Supplier가 상품을 생산하는 동안 다른 상품 공급 요청(RFQ)이 들어오면 2번부터 4번의 과정을 반복한다.
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)
// 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를 하나 더 만들었는데...
아..보지 않아서 잘 모르겠다는..ㅋㅋ
어차피 메시지는 모델간에 정보를 넘겨주는 거기 때문에 안에 가지고 있는 정보가 뭐냐가 중요한 거라는...
몇 개가 되도 상관은 없다..ㅋㅋ
요건 참고자료...
앞 부문은 지금 교재로 쓰고 있는 (말이 좋아 교재지..이 책으로 진도를 나가는 것은 아닌..ㅡ_ㅡ) “Semantic Web Technologies”, Davies, J., R. Studer and P. Warren, WILEY
요 책의 chapter 9를 리뷰한 거고...
후반부는 NeOn Methodology를 간단하게 소개한 것으로
NeOn project 홈페이지에 가면 공개되어 있는 자료를 바탕으로 했다.
Supplier가 Auctioneer에게 판매할 상품의 경매를 요청한다. (이때 상품의 초기 시작 가격 (Initial Price)을 같이 보낸다.) ' 위 그림의 청색 라인이 경매 시작 신호선이다.
Auctioneer는 N개의 Customer에게 Supplier에게 받은 동일한 메시지를 전달하여 경매가 시작 되었음을 알린다.
각각의 Customer는 자신만의 가격 탄력성 (Price Elasticity)와 최대 입찰 가능 가격(Maximum Boundary Price)을 가지고 있다.
최초의 입찰에서는 각각의 Customer가 입찰 가격으로 Auctioneer로부터 전달 받은 초기 입찰 가격에 자신의 가격 탄력성 안에서 가격을 설정(Rand 함수를 이용하여 자신의 가격 탄력성 안에서 랜덤 하게 선택한다.) 하여 입찰 가격을 정해 Auctioneer에게 보낸다. ->빨간색 점선 First Bidding Price = Initial Price from Auctioneer + Rand(Price Elasticity of Customer)
첫 번째 입찰을 받은 Auctioneer는 최초 입찰에서 최고가를 입찰한 Customer와 입찰 최고가를 각각의 Customer 및 Supplier에게 보낸다.
두 번째 입찰은 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;
5번을 다시 실행
입찰은 총 5회 진행 된다. (※ 5회 이전에 입찰자가 1명만 남은 경우에는 그 입찰자의 입찰가격을 낙찰 가격으로 하고 경매를 종료 시킨다.) 5회 입찰 진행 후 최고가를 입찰한 Customer가 낙찰되며, 낙찰 가격을 모든 Customer와 Supplier에 공지 하고 경매는 종료 된다.
경매 종료 메시지를 전달받은 Supplier는 재고에 남아있는 상품의 경매 요청 메시지를 최초 가격과 함께 Auctioneer에게 전달한다.
1~9의 과정을 반복하여 supplier에 더 이상 재고가 존재하지 않을 경우 시스템을 종료한다.
Procedure and Design
DEVS로 구성 시 만들어지는 1개의 Digraph 모델과 3종류의 Component(Atomic Model)와 3종류의 Message로 구성된다.
Auction: gpt.java를 수정하여 만든다. (Digraph Model)
Supplier : genr.java를 수정하여 만든다.
Supplier는 자신의 상품이 저장된 Inventory를 가진다.
또한, Auctioneer로부터 받은 Result Message를 통해 경매가 종료되었을 경우 Start Message를 전송하여 새로운 상품의 경매를 요청한다. [필수 variables] 상품 저장소 (int형 2차원 배열 inventory-상품번호와 시작가격 포함)
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)
Customer : proc.java를 수정하여 만든다.
자신의 판매전략에 맞춰 입찰가를 선정하나 만약 선정된 가격이 입찰 한도를 초과할 경우 입찰가를 0으로 조정한다.
그리고, 만약 경매가 종료되었을 경우에는 Bidding Message를 발생시키지 않고 입찰가를 0으로 재조정한다. [필수 variables] 입찰가 (int형 bid_price), 가격 탄력성(int형 PE), 입찰 한도(int형 MBP), 현재가격 (int형 posted_price)
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;
}
}
이번 시간엔 Minimum Load First Scheduling Model을 맹글어보았다.
말그대로, 지난 시간의 Round Robin Scheduling처럼 생성되는 job을 순서대로 processor에 한개씩 한개씩 보내는 것과는 달리
5개의 프로세서 중 현재 가장 적은 Workload를 가진 processor에게 job을 주겠다는 뜻이다.
그렇다면 Round Robin Scheduling에서 변경되어야 할 몇 가지를 살펴보면,
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감소
가장 Workload가 적은 processor를 계산하는 부분이 필요하다.
Bubble Sort를 사용하는데, sorting방법은 어떤 것을 사용해도 관계없다.
현재 상태에서 가장 workload가 적은 processor에 job을 할당한다.
모든 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이다.
네 번째 시간에는 Round Robin Scheduling Model을 만들었다아...
스케줄러를 만들고 이 녀석이 여러 개의 프로세서에 순차적으로 job을 보내주는 역할을 하는 거다.
각 프로세서는 queue로 되어 있어서, scheduler로 부터 받은 job을 차곡차곡 넣어놓고 처리하다가
queue 크기를 초과하게 되면 job loss가 발생한다.
각 모델이 하는 일과 변수를 좀 더 자세히 설명한 것이다...
Generator (Atomic Model)
Generates a job every int_arr_time and send it to Scheduler.
Variables : int_arr_time(int), job_count(int)
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…)
※ 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.
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).
우리가 만들어야 하는 파일은 다섯개이다.
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
Make the loss_message.java, which is modified from the job.java file. Loss_message includes the processor number and its job loss count.
Make the scheduler.java, which is modified from the proc.java.
Make the processor.java, which is modified from the procQ.java. But, the queue of processor has the fixed size of 10.
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));
}
}
벌써 4주나 강의가 진행되었고, 오늘 바로 그 4주째 강의의 실험을 해야 하기땜시
내친 김에 모조리 포스팅 해버려야겠다.
어차피 복습도 좀 필요하고 말야...
세 번째 시간은 아주 간단한 걸 했다...
(그치만 4주째는 완전 초토화였다는거...ㅜ_ㅜ)
요 모델은 지난 포스팅에 익히 보았던 gpt 모델이지만, 한 가지 다른 점이 있다.
세 개의 atomic model을 사용한 것이 아니라, EF라는 diagraph model을 사용한 것이다.
요 EF는 generator와 transducer를 합쳐놓은 것이다.
뭐 조금 단정한 느낌이 드나?
generator와 transducer 간에 서로 전달되어야 하는 메시지가 많으니 합치는 것이 더 좋을지도...
세 번째 시간에 할 일은...
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).
What is the total turn_arround_time?
What is the average of turn_arround_time?
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이다.
성능 관련 계산 값들이 포함되어 있으므로 확인하면 될듯...
그냥 쭉 훑어보기만 했다는..ㅋㅋㅋ
두 번째 시간에는 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에게 다시 전달된다.
아웅...이런 간단한 것도 설명하기 참 어렵군하...ㅜ_ㅜ
노파심에 다시 한 번 적는 건...
이 포스팅은 복습의 의미이기 때문에 틀린 정보가 들어있을지도 모른다는 것...
뭐 별로 참고할 것도 없지만, 혹시 참고하다가 틀린 점이 있으면 지적해주시는 센수~^^*
자, 그럼 두번째 시간에 해야 할 일은 무엇인고 하니...
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.
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)
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;
}
}