멀티 부트를 하던 도중에 디스크에는 있는데, grub 에서 못 찾는 것은 우분투에 들어가서
update-grub
을 해주면 쉽게 해결됩니다.
이건 검색해보면 쉽게 해결되는 문제구요.
제가 경험한 문제는 grub 선택 화면에는 windows 가 뜨는 데 선택하면 다시 grub 선택화면으로 되돌아오는 문제였습니다.
부트 로더 설정을 이상하게 했더니 windows (정확히는 windows 10) 로 부팅이 안되는 거죠.
검색을 해봤더니
http://askubuntu.com/questions/725290/grub-windows-10-doesnt-start-anymore
와 같은 방법이 있고 이걸로 해결했습니다.
ntldr 이 뭔지 검색해보니
NTLDR는 NT 로더(NT Loader)의 준말로, 마이크로소프트 윈도우 NT 계열 운영 체제를 위한 시동 로더이다. 이를테면 윈도우 XP와 윈도우 서버 2003을 들 수 있다.
라는 군요. 그러니까 windows 10 의 부팅 로더가 어디있는지 grub에 지정을 해주는 것으로 해결된 것으로 보입니다.
점점 부팅 및 기타 등등에 대해 알 수 없게 되어지네요. 너무 복잡해...
2016/12/30
2016/07/25
암벽화 구분하기.
클라이밍을 시작한지 2년째, 자연암벽은 1년째인 새내기에 불과한 제가 이런 글을 쓰는 게 우습지만, 그래도 지금까지 암벽화에 관해서 느낀 점에 관해서 써보겠습니다.
암벽을 등반할 때 암벽화는 발을 보호할 뿐 하니라, 발의 힘을 벽에 전달하는 데 유용합니다.
암벽화를 신은 X-ray 사진입니다. (출처: http://huzunludonenceler.tumblr.com/ and http://huzunludonenceler.tumblr.com/post/49715436297)
사진에서 보다시피 엄지발가락이 삼각형 (아치모양)으로 구부러져 있습니다. 발가락 뼈가 ^^ 모양으로 구부러져서 코어에서부터 시작되는 힘을 다리를 거쳐 발가락끝까지 보낼 수 있게 되는 것 같습니다.
일반적으로 암벽화를 구분하는 건 너무나 잘 되어 있습니다. 굳이 여기서 그 얘기까지 할 필요는 없을 것 같습니다. 그런데 신다보니 그 이전의 차이 이외에도 한가지 더 차이점이 느껴지더군요.
바로 토박스의 크기에 관한 차이점입니다.
우리나라 브랜드 부토라에서 생산 판매하는 아크로입니다.
발끝에서부터 발등까지 고무로 되어 있습니다. 그래서 잘 늘어나지도 않는 반면에 발에 길들여지기 까지 (혹은 발이 길들여지기 까지) 시간이 좀 걸립니다. 대신 한번 신으면 발을 꽉 잡아줘서 안정감이 듭니다.
5.10 의 아나사지입니다.
위의 아크로와 달리 발끝에서 시작하는 고무가 엄지발가락 정도까지만 덮습니다. 신발끈으로 넓이를 조절할 수 있어서 사자마자 편하게 사용할 수 있습니다.
이볼브의 뉴샤만입니다.
아크로와 아나사지의 중간정도까지 고무로 덮혀있습니다.
토 후킹할 때 발등의 고무가 중요한 것 같습니다. (초보다 보니 토 후킹할 일이 별로 없어서... --;;)
좀 더 옆을 파서 편안함과 힘의 전달, 양쪽을 다 취하려 한 것 같습니다.
라 스포르티바의 스콰와마도 모양이 비슷하죠. 드라고는 편하다는 소문이 있구요, 스콰와마도 보기와는 다르게 신으면 매우 편하더군요.
그러니까 홀드를 딛고 서는 힘이 약하신 분은 토박스가 큰 게 나을 것 같구요, 내공이 되시는 분은 아무거나 알아서 신으시는 게 나을 것 같습니다.
이만 실력은 없는데, 자꾸 좋은 암벽화가 나오니 예전 암벽화도 신어보고싶고, 새로나오는 암벽화도 신어보고 싶은 지름신이 강림하고 있는 1인이었습니다. ^^
암벽을 등반할 때 암벽화는 발을 보호할 뿐 하니라, 발의 힘을 벽에 전달하는 데 유용합니다.
암벽화를 신은 X-ray 사진입니다. (출처: http://huzunludonenceler.tumblr.com/ and http://huzunludonenceler.tumblr.com/post/49715436297)
사진에서 보다시피 엄지발가락이 삼각형 (아치모양)으로 구부러져 있습니다. 발가락 뼈가 ^^ 모양으로 구부러져서 코어에서부터 시작되는 힘을 다리를 거쳐 발가락끝까지 보낼 수 있게 되는 것 같습니다.
일반적으로 암벽화를 구분하는 건 너무나 잘 되어 있습니다. 굳이 여기서 그 얘기까지 할 필요는 없을 것 같습니다. 그런데 신다보니 그 이전의 차이 이외에도 한가지 더 차이점이 느껴지더군요.
바로 토박스의 크기에 관한 차이점입니다.
우리나라 브랜드 부토라에서 생산 판매하는 아크로입니다.
5.10 의 아나사지입니다.
이볼브의 뉴샤만입니다.
아크로와 아나사지의 중간정도까지 고무로 덮혀있습니다.
토 후킹할 때 발등의 고무가 중요한 것 같습니다. (초보다 보니 토 후킹할 일이 별로 없어서... --;;)
아나사지와 같이 발등을 덮는 부분이 좁다고 해서 토 후킹이 안 걸리는 건 아닙니다.
토 후킹도 토 후킹이지만, 요새 트렌드가 편한 암벽화를 찾는 추세고 메이커도 그에 맞춰서 편한 암벽화를 만들려다보니 밑창이 얇아질 수 밖에 없고, 그럼 힘을 제대로 전달할 수 없으니 밑창을 얇게 하는 만큼 발등부분에 고무를 씌워서 힘을 전달할 수 있게하는 것 같습니다. 대신 좀 갑갑함을 느낄 수도 있구요.
그래서 스카르파의 드라고 같은 경우에는
그러니까 홀드를 딛고 서는 힘이 약하신 분은 토박스가 큰 게 나을 것 같구요, 내공이 되시는 분은 아무거나 알아서 신으시는 게 나을 것 같습니다.
이만 실력은 없는데, 자꾸 좋은 암벽화가 나오니 예전 암벽화도 신어보고싶고, 새로나오는 암벽화도 신어보고 싶은 지름신이 강림하고 있는 1인이었습니다. ^^
2015/10/13
백 패킹과 캠핑
( 이 글을 쓰는 이유는 보시고 참고하라는 것이 아닌, 저 스스로 정리해보고 나중에 '저'한테 도움이 되고자 쓰는 것으로, 혹시 잘못된 내용이나 모자란 부분이 있으면 알려주시면 감사하겠습니다. 이 글을 보시고 그대로 따라하시다가 손실 혹은 손해를 보시더라도 그 선택의 책임은 따라하신 분에게 있지 저한테는 없음을 알려드립니다. ^^;; )
요즘 암벽타는 재미에 산에 갈 날만 기다리고 있습니다. 등산화신고 배낭에 먹을 거 조금싸고 당일로 북한산 갔다오는 것도 재미있지만, 암벽을 타니 그건 또 다른 세상이더군요. 트레킹은 트레킹대로, 암벽은 암벽대로 재미있습니다.
다니던 암장에서 암벽반 수강을 하며 총 5주 강의를 받았는데, 1,2,3주 차 때에는 기초적인 슬랩 등반, 크랙 등반, 페이스 등반 & 멀티 피치 (2피치) 연습을 했고, 4주차때에는 노적봉, 5주차에는 설악산으로 2박3일 암벽등반을 했더랬습니다. 우리나라에는 산도 많고 강도 많아, 당일치기 암벽 등반도 가능하죠. 북한산 인수봉에는 매주 주말에는 사람들로 바글대구요. 근데 설악산 암벽을 2박 3일로 가니 그건 또 색다른 재미를 주더군요. 야영을 하고나서 아침을 먹고, 어프로치하는데 2,30분 정도 밖에 안드니 시간도 아끼고, 체력도 아끼고, 거기에 야영의 재미까지 말이죠.
설악산 야영을 해야되는데, 야영 장비는 없고, 사자니 뭘 사야할 지도 모르겠고해서 캠핑을 자주 다니는 친구한테서 텐트와 침낭, 매트리스, 코펠을 빌렸더랬습니다. 각자 준비하라길래 나름 민폐 안끼친다고 빌렸더랬죠. 그런데 가보니 캠핑을 위한 장비와 등반을 위한 야영을 위한 장비는 전혀 다르더군요. 물론 이번에는 야영장이 있어서 자동차에서 바로 짐을 내릴 수 있었지만, 차 안에 짐만 싣는 것도 아니고 사람도 타야하니 빌려온 텐트는 아예 두고 떠났습니다. 게다가 다들 코펠을 들고오니 코펠에 냄비가 여러개 든 제가 빌린 코펠은 필요도 없더군요. 그래서 빌린 장비 중에 쓴건, 침낭과 매트리스뿐이었습니다.
그렇게 우여곡절 끝에 야영을 끝내고 돌아오니 장비에 관한 관심이 생기더군요. 가기 전엔 뭐가 뭔지도 몰랐는데, 한번보니 대강이라도 어떤 장비를 어떤 때 사용해야하는 지 감이 오더군요. 그래봐야 야영 한번에 암벽 5번 탄 생초보이지만 그러려니 하시기 바랍니다. ^^;;
백 패킹에 가장 기본적인건, '손이 자유로워야 하고, 때문에 배낭에 다 실려야한다' 인것 같습니다. 저는 상담을 거쳐서 70L 짜리 배낭을 구입했는데, 거기에 텐트, 침낭, 매트리스, 코펠, 암벽 장비 ( + 암벽탈 때 쓸 배낭 ), 먹을 것 + 기타등등이 실려야하는 겁니다. ( 전 옷만 가득 담았습니다. 완전 낭비였죠. TT )
그런데 캠핑을 위한 장비는 굳이 배낭에 들어갈 필요가 없죠. 야영장에 차로 도착해서 멀어야 몇십미터 가서 짐 풀면 되니까요. 편안한 캠핑을 위해선 텐트도 넉넉히 커야할 것이고, 여럿이서 캠핑 가는 게 아닌 한 가족 단위로 가면 코펠도 4,5개의 냄비가 필요할 겁니다. 그런데 암벽 등반은 기본적으로 최소 2명에 4,5명까지도 늘어나니 각자 냄비 1개씩만 들고와도 밥짓고 국끓이는 데 전혀 문제가 없죠. 그래서 각 장비 별로 차이점과 나름대로 알아본 것들을 정리해보겠습니다.
장비를 준비하는 순서
요즘 암벽타는 재미에 산에 갈 날만 기다리고 있습니다. 등산화신고 배낭에 먹을 거 조금싸고 당일로 북한산 갔다오는 것도 재미있지만, 암벽을 타니 그건 또 다른 세상이더군요. 트레킹은 트레킹대로, 암벽은 암벽대로 재미있습니다.
다니던 암장에서 암벽반 수강을 하며 총 5주 강의를 받았는데, 1,2,3주 차 때에는 기초적인 슬랩 등반, 크랙 등반, 페이스 등반 & 멀티 피치 (2피치) 연습을 했고, 4주차때에는 노적봉, 5주차에는 설악산으로 2박3일 암벽등반을 했더랬습니다. 우리나라에는 산도 많고 강도 많아, 당일치기 암벽 등반도 가능하죠. 북한산 인수봉에는 매주 주말에는 사람들로 바글대구요. 근데 설악산 암벽을 2박 3일로 가니 그건 또 색다른 재미를 주더군요. 야영을 하고나서 아침을 먹고, 어프로치하는데 2,30분 정도 밖에 안드니 시간도 아끼고, 체력도 아끼고, 거기에 야영의 재미까지 말이죠.
설악산 야영을 해야되는데, 야영 장비는 없고, 사자니 뭘 사야할 지도 모르겠고해서 캠핑을 자주 다니는 친구한테서 텐트와 침낭, 매트리스, 코펠을 빌렸더랬습니다. 각자 준비하라길래 나름 민폐 안끼친다고 빌렸더랬죠. 그런데 가보니 캠핑을 위한 장비와 등반을 위한 야영을 위한 장비는 전혀 다르더군요. 물론 이번에는 야영장이 있어서 자동차에서 바로 짐을 내릴 수 있었지만, 차 안에 짐만 싣는 것도 아니고 사람도 타야하니 빌려온 텐트는 아예 두고 떠났습니다. 게다가 다들 코펠을 들고오니 코펠에 냄비가 여러개 든 제가 빌린 코펠은 필요도 없더군요. 그래서 빌린 장비 중에 쓴건, 침낭과 매트리스뿐이었습니다.
그렇게 우여곡절 끝에 야영을 끝내고 돌아오니 장비에 관한 관심이 생기더군요. 가기 전엔 뭐가 뭔지도 몰랐는데, 한번보니 대강이라도 어떤 장비를 어떤 때 사용해야하는 지 감이 오더군요. 그래봐야 야영 한번에 암벽 5번 탄 생초보이지만 그러려니 하시기 바랍니다. ^^;;
백 패킹에 가장 기본적인건, '손이 자유로워야 하고, 때문에 배낭에 다 실려야한다' 인것 같습니다. 저는 상담을 거쳐서 70L 짜리 배낭을 구입했는데, 거기에 텐트, 침낭, 매트리스, 코펠, 암벽 장비 ( + 암벽탈 때 쓸 배낭 ), 먹을 것 + 기타등등이 실려야하는 겁니다. ( 전 옷만 가득 담았습니다. 완전 낭비였죠. TT )
그런데 캠핑을 위한 장비는 굳이 배낭에 들어갈 필요가 없죠. 야영장에 차로 도착해서 멀어야 몇십미터 가서 짐 풀면 되니까요. 편안한 캠핑을 위해선 텐트도 넉넉히 커야할 것이고, 여럿이서 캠핑 가는 게 아닌 한 가족 단위로 가면 코펠도 4,5개의 냄비가 필요할 겁니다. 그런데 암벽 등반은 기본적으로 최소 2명에 4,5명까지도 늘어나니 각자 냄비 1개씩만 들고와도 밥짓고 국끓이는 데 전혀 문제가 없죠. 그래서 각 장비 별로 차이점과 나름대로 알아본 것들을 정리해보겠습니다.
- 텐트
- 캠핑용
- 한 가족이 다 들어갈 정도로 넉넉한 공간이 되어야하고, 4인용이나 5인용 정도되면 배낭안에 안 들어갈 겁니다. 즉, 등반을 위한 야영용으로는 사용 못합니다.
- 어차피 배낭 안에 안 들어갈거면 방 하나짜리 보다는 거실이 있는 투룸이 나을 것 같습니다.
- 등반용
- 극단적으로는 '나만' 들어가도 됩니다.
- 게다가 무게도 관건이기 때문에 더블월 (텐트의 천이 2개) 보다 싱글월 (텐트의 천이 1개) 을 선호하기도 하는 것 같습니다. 다만 응결된 물방울을 견딜 수 있다면 말이죠.
- 텐트를 편 상태말고도 수납을 한 상태도 보아야 합니다. 배낭에 안 실리면 안되죠.
- 폴 무게 조차도 줄이기 위해, 등산용 스틱을 지지대로 사용하는 모델도 있습니다.
- 날씨가 좋을 때에는 아예 타프만 치고 매트리스와 침낭만으로 야영을 하기도 한답니다.
- 침낭
- 캠핑용
- 솜이던 집에서 쓰던 헌 이불이던 뭐던 상관없을 것 같습니다. 좀 춥더라도 난방기구를 사용할 수 있으니까요.
- 등반용
- 침낭에 대한 유럽 산업표준이 있더군요. EN 13537 이라고 하는데요. 이 기준으로 필요한 침낭을 선택하면 될 것 같습니다.
- 여름용 침낭, 3계절용 침낭, 겨울용 침낭으로 나누는 것 같습니다. 겨울에 야영할 것 아니면 3계절용 정도로 충분할 듯 싶네요.
- 별도의 난방기구를 들고 다니지는 못할 거고, 잘해야 핫팩이나 버너 정도이니 추위를 막기 위해선 비싸더라도 좋은 침낭을 사는 게 낫지 않을까 싶습니다. 즉, 몸으로 때웁니다.
- 코펠
- 캠핑용
- 한 가족이 밥, 국 + 기타등등을 해야되니 냄비가 여러개 있는 코펠이 필요합니다.
- 등반용
- 냄비가 하나짜리 코펠이면 충분. (같이 간 사람이 안가져오면 대략 난감)
- 버너
- 캠핑용
- 밥도 하고 국도 끓이고 고기도 구워먹어야 하니 가스 버너에 모닥불 피울 난로에 기타등등 2,3개 있으면 좋겠네요.
- 등반용
- 작고 가볍고 코펠이 올라가기만 하면됨.
- 백패킹용 버너를 소개해주는 동영상을 보니, 가스, 알코올, 고체연료, 나뭇가지를 이용한 버너를 알려주더군요.
- 어떤 분은 가솔린을 원료로 하는 버너도 가지고 계시더군요. 화력은 가솔린이 최고였습니다.
- 조명
- 캠핑용
- 크면 어떻습니까, 텐트 줄에 애들이 걸려서 넘어지지 않을 정도로 환해야지요.
- 전기 들어오는 야영장이면 전기 걱정 안 해도 될거구요. 발전기 들고가면 전기 걱정도 없겠죠.
- 등반용
- 헤드 랜턴 하나로 다 처리합니다.
장비를 준비하는 순서
- 우선 배낭을 준비해야하는데, 자신이 감당할 수 있는 무게를 알아야 하겠습니다. 배낭이 클수록 배낭 자체의 무게가 많이 나가기 때문에, 연약한 분은 좀 작은 배낭을, 건장한 분은 큰 배낭을 선택해야 하겠습니다.
- 배낭의 어느 부분에 어떤 장비를 채워넣을 것인지 결정한 후에 크기에 맞는 장비를 선택합니다. 밖에 텐트를 매달지, 매트리스를 매달지, 아니면 아무것도 안 매달지. 비용을 생각하며 장비를 고르는 재미도 쏠쏠하더군요.
- 백패킹용 장비는 보통 암벽 장비를 판매하는 곳에서 구하는 게 편할 것 같습니다.
2015/08/05
vi에서 패턴을 이용해 동일한 구문 바꾸기
vi에서 HTML문서를 수정하다보니,
<a href="http://..../html/...."></a>
와 같은 구문에서 http에서부터 html까지 "."로 일괄적으로 바꾸고 싶을 때 사용하는 구문입니다.
command mode에서
s / pattern (바꾸고 싶은 문자열) / string (바꿀 문자열) / option
을 쓰면 됩니다.
pattern 은 정규표현식도 가능합니다. 다만 vi나 vim에서 쓰는 건 조금 다를 수 있으니, :help 를 이용해서 사용법을 알아보시면 되겠습니다.
예를 들어, http에서부터 html까지 .로 바꾸려면,
예:
:s/http.\{-}html/./c
로 해주면 커서가 있는 줄에 있는 http에서부터 바로 다음 html까지 찾아서 .로 바꿔줍니다. 코드에서 \{-}는 정규표현식의 non greedy 표현입니다. c는 옵션으로 확인 절차가 한번 들어갑니다.
파일 전부에서 바꿔주고 싶으면 s앞에 %를 붙여주면 됩니다.(:help range 참조)
:g/http.\{-}html/./c
2015/07/30
python 3를 이용해서 다음 사전에서 단어 찾아오기
bash공부를 하는데, bash 매뉴얼이 번역된 게 없더군요. 그래서 공부도 할 겸 번역을 하려고 하는데, 모르는 단어가 너무 많아서 다음 사전의 신세를 지려고 했는데, 매번 웹페이지로 들어가서 텍스트 박스에 단어 넣고 검색하는 게 귀찮더군요. 그래서 python 3로 다음 사전에서 찾고자 하는 단어를 찾는 스크립트를 만들어봤습니다.
우선, urllib3와 BeautifulSoup, sys, re 가 설치되어 있어야겠습니다.
------ code 시작 ------
좀 보기 흉해도 조금 편해질 것 같네요. 정규표현식 ( regular expression )을 잘 사용하면 괜찮을 것 같은데, 쉽지않네요.
그래도 참고로만 할 꺼니까 괜찮을 것 같네요.
우선, urllib3와 BeautifulSoup, sys, re 가 설치되어 있어야겠습니다.
------ code 시작 ------
#!/usr/bin/python3
import urllib3
import bs4
import sys
import re
# 알고자 하는 단어를 입력받습니다.
word = input('단어를 입력하세요: ')
# http 입력을 받기 위한 url 문자열을 만듭니다.
url = 'http://dic.daum.net/search.do?q=' + word
# urllib3를 이용해서 자료를 받습니다.
http = urllib3.PoolManager()
r = http.request( 'GET', url )
# urllib3에서 자료를 제대로 받아온 것을 확인합니다.
# 제대로 읽어오지 못했으면 스크립트를 종료합니다.
if r.status != 200:
print( '자료를 읽어오지 못했습니다.' )
print( 'urllib3 에러코드:', r.status )
sys.exit( r.status )
# 읽어온 자료를 BeautifulSoup을 이용해 파싱해줍니다.
daumDic = bs4.BeautifulSoup( r.data )
# 읽어온 자료 중에서 단어들만 추출해냅니다.
# 우선 태크 중에서 필요한 부분만을 추출해냅니다.
korWords = daumDic.findAll('div', attrs={'class':'txt_means_KUEK'} )
# 태크들을 각각 지워야 할 필요가 생겼습니다.
# 파싱을 하니 원하는 모습으로 깔끔하게 되질 않더군요.
# 각 라인을 읽다가 '<'가 시작되면 단어를 읽지 않고, '>'가 나오면 글자를 저장해서 출력하는
# 방식으로 해보겠습니다.
for line in korWords:
# 빈칸들을 없애주고
line = str(line).replace( ' ', '' )
# 저장할 장소를 마련해둡니다.
word = ''
# flag는 저장해도 좋을 지를 알려주는 역할을 합니다.
flag = True
# 한 글자씩 찾아나갑니다.
for cha in line:
# 태그가 시작하면 flag를 False로 만들어 저장하지 않습니다.
if cha == '<':
flag = False
# 태그가 끝나면 flag를 True로 만들어 저장합니다.
if cha == '>':
flag = True
if flag:
word += str(cha)
# 이하는 결과물을 보기 좋게 정리해주는 역할을 합니다.
# 좀 너저분하네요.
resultWord = ''
# 위의 상태로 저장하게 되면 >부터 저장하기 때문에 >가 남게 됩니다.
# 보기 흉하니 전부 빈칸으로 만듭니다.
word = word.replace( '>', ' ')
# 그럼 빈칸이 2개 이상 생기는 경우도 생깁니다.
# 보기 흉하니 빈칸을 기준으로 쪼개서, 빈칸을 1개로만 해줍니다.
for w in word.split():
resultWord += w + ' '
# 결과물을 출력합니다.
print( resultWord )
--------- code 끝 ------------
좀 보기 흉해도 조금 편해질 것 같네요. 정규표현식 ( regular expression )을 잘 사용하면 괜찮을 것 같은데, 쉽지않네요.
그래도 참고로만 할 꺼니까 괜찮을 것 같네요.
혹시 bash매뉴얼번역에관심있으신분은
https://github.com/ptjoker95/bash_document_translate_Korean
를 참고해주세요.
2015/07/27
윈도우 8.1에 itunes 설치하기
무선 업데이트가 된 이후로 itunes를 써본 적이 없는데, 마눌님께서 CD에 있는 음악을 넣어달라는 퀘스트를 주는 바람에 설치해봤습니다.
그런데, Windows 8.1에 itunes 버전 12.x 가 안 깔리는 겁니다. 관리자 계정으로 깔아도 안되고, 자꾸 iPhone과 연결할 수 없다는 메세지만 뜨면서 설치가 안되더군요.
그래서 우선은 예전 버전(10.x)을 깔아봤습니다. 이건 됩니다. 그런데 버전이 낮아서 iPhone과 연결이 안됩니다. TT
iTunes에서 해주는 업그레이드를 실행시켰더니 역시나 이전의 에러가 뜨면서 이젠 예전 버전도 실행이안됩니다.
웹을 이리저리 뒤져본 결과, .Net Framework 버전 2과 버전 3이 깔려야 된다더군요. 그래서 다운로드 받아서 설치를 해봤는데, 이게 설치가 된 건지 안 된건지 알 수가 없더군요.
혹자는 설정에 있는 서비스에 들어가서 Apple Mobile Service (? 맞나 모르겠네요. 서비스 중에 Apple 들어가는 건 그거 밖에 없으니.. --;; )를 껐다켜라, Bonjour를 껐다켜라라던데, 안 먹힙니다. 소용없습니다. ㅋㅋ
이것저것 해보다가 iTunes 버전 12 중에 좀 낮은 버전을 설치했더니 되더군요. --;;
구글에서 "itunes lower version"으로 검색하면 나올 겁니다.
추측컨데, Apple Mobile 머시기라는 서비스가 .Net Framework을 쓰는데, 새 버전인 4.5버전과 충돌이 있는 것 같습니다. 뭐 곧 패치가 나오겠죠.
아니면 64bit를 쓰는데, 그게 문제일 수도 있구요.
요약:
- iTunes를 쓰려면 .Net Framework 2.x 3.x 버전이 필요할 수도 있다.
- 그래도 안되면 예전 버전으로 설치해서 쓰다가 패치되면 쓰세요.
그런데, Windows 8.1에 itunes 버전 12.x 가 안 깔리는 겁니다. 관리자 계정으로 깔아도 안되고, 자꾸 iPhone과 연결할 수 없다는 메세지만 뜨면서 설치가 안되더군요.
그래서 우선은 예전 버전(10.x)을 깔아봤습니다. 이건 됩니다. 그런데 버전이 낮아서 iPhone과 연결이 안됩니다. TT
iTunes에서 해주는 업그레이드를 실행시켰더니 역시나 이전의 에러가 뜨면서 이젠 예전 버전도 실행이안됩니다.
웹을 이리저리 뒤져본 결과, .Net Framework 버전 2과 버전 3이 깔려야 된다더군요. 그래서 다운로드 받아서 설치를 해봤는데, 이게 설치가 된 건지 안 된건지 알 수가 없더군요.
혹자는 설정에 있는 서비스에 들어가서 Apple Mobile Service (? 맞나 모르겠네요. 서비스 중에 Apple 들어가는 건 그거 밖에 없으니.. --;; )를 껐다켜라, Bonjour를 껐다켜라라던데, 안 먹힙니다. 소용없습니다. ㅋㅋ
이것저것 해보다가 iTunes 버전 12 중에 좀 낮은 버전을 설치했더니 되더군요. --;;
구글에서 "itunes lower version"으로 검색하면 나올 겁니다.
추측컨데, Apple Mobile 머시기라는 서비스가 .Net Framework을 쓰는데, 새 버전인 4.5버전과 충돌이 있는 것 같습니다. 뭐 곧 패치가 나오겠죠.
아니면 64bit를 쓰는데, 그게 문제일 수도 있구요.
요약:
- iTunes를 쓰려면 .Net Framework 2.x 3.x 버전이 필요할 수도 있다.
- 그래도 안되면 예전 버전으로 설치해서 쓰다가 패치되면 쓰세요.
2015/07/23
초등학교 4학년 막대그래프 그리기
파이선 스크립트로 간단한 막대그래프 그리기를 만들어봤습니다. 정말 간단합니다. ^^;;
--------------------------
#-*- coding: utf-8 -*-
import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams
X = []
Y = []
while True:
try:
x = input("input X: ")
except:
break
if x == '':
break
try:
y = input("input Y: ")
except:
break
if y == '':
break
if type(x) is not str:
if int(x) == float(x):
x = int(x)
else:
x = float(x)
if int(y) == float(y):
y = int(y)
else:
y = float(y)
X += [x]
Y += [y]
if len(X) == 0:
sys.exit()
ind = np.arange( len(X) )
width = 0.35
plt.plot()
plt.bar( ind, Y, 0.3 )
plt.xticks( ind+width/2., X, family = ['Noto Sans Korean'] )
plt.ylim( 0, max(Y) + int( max(Y)/10.0 ) )
plt.show()
--------------------
numpy가 필요없을 것 같은데, 기왕 집어넣은 거 냅두기로 했습니다.
- python버전은 3.x입니다.
- 우분투(리눅스) 환경에서 구동해봤습니다.
--------------------------
#-*- coding: utf-8 -*-
import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams
X = []
Y = []
while True:
try:
x = input("input X: ")
except:
break
if x == '':
break
try:
y = input("input Y: ")
except:
break
if y == '':
break
if type(x) is not str:
if int(x) == float(x):
x = int(x)
else:
x = float(x)
if int(y) == float(y):
y = int(y)
else:
y = float(y)
X += [x]
Y += [y]
if len(X) == 0:
sys.exit()
ind = np.arange( len(X) )
width = 0.35
plt.plot()
plt.bar( ind, Y, 0.3 )
plt.xticks( ind+width/2., X, family = ['Noto Sans Korean'] )
plt.ylim( 0, max(Y) + int( max(Y)/10.0 ) )
plt.show()
--------------------
numpy가 필요없을 것 같은데, 기왕 집어넣은 거 냅두기로 했습니다.
- python버전은 3.x입니다.
- 우분투(리눅스) 환경에서 구동해봤습니다.
파이선 3 (python 3)에서 matplotlib으로 그래프만들때 한글 집어넣기
파이션 공부하다보니 그래프 그릴 일이 있더군요. 그래서 matplotlib( http://matplotlib.org/1.3.1/index.html )을 사용하기로 했습니다. 조금만 공부하면 금방 도표그릴 수 있습니다.
그런데 좌표에 한글을 넣을 일이 있는데, 기본값으로 하면 그냥 깨지더군요. 이것저것 뒤져보다 알게된 걸 올립니다.
X축에 글자를 넣으려고 하면 xticks( http://matplotlib.org/1.3.1/api/pyplot_api.html?highlight=xticks#matplotlib.pyplot.xticks )를 쓰게 됩니다. 그리고 xticks는 args로 Text( http://matplotlib.org/api/text_api.html#matplotlib.text.Text.set_fontproperties )를 쓸 수 있습니다. 이 text의 Property에 보면 family( http://matplotlib.org/api/text_api.html#matplotlib.text.Text.set_family )가 있습니다. 이 값을 컴에 설치되어 있는 한글폰트값으로 설정해주면 한글이 떡 나타나게 됩니다.
예) plt.xticks( ind+width/2., X, family = ['Noto Sans Korean'] )
아주~~ 편합니다.
그런데 좌표에 한글을 넣을 일이 있는데, 기본값으로 하면 그냥 깨지더군요. 이것저것 뒤져보다 알게된 걸 올립니다.
X축에 글자를 넣으려고 하면 xticks( http://matplotlib.org/1.3.1/api/pyplot_api.html?highlight=xticks#matplotlib.pyplot.xticks )를 쓰게 됩니다. 그리고 xticks는 args로 Text( http://matplotlib.org/api/text_api.html#matplotlib.text.Text.set_fontproperties )를 쓸 수 있습니다. 이 text의 Property에 보면 family( http://matplotlib.org/api/text_api.html#matplotlib.text.Text.set_family )가 있습니다. 이 값을 컴에 설치되어 있는 한글폰트값으로 설정해주면 한글이 떡 나타나게 됩니다.
예) plt.xticks( ind+width/2., X, family = ['Noto Sans Korean'] )
아주~~ 편합니다.
2015/07/21
하나의 디스크에 Windows 8.1과 우분투 15.04 멀티 부팅 시키기 (GRUB)
간만에 컴을 들여놨습니다.
대강의 구성은 intel i3, ssd + hdd 구요. ssd에 윈도우와 우분투를 같이 깔기로 했습니다.
파티션은 절반으로 나누고, 앞쪽에 Windows 8.1을 뒤쪽에 우분투 15.04를 깔았습니다.
우선 Windows 8.1를 깔았습니다. ssd라서 금방 깔리더군요. 부팅도 정말 빠릅니다. 읽고 쓰는데 횟수 제한이 있다는 것만 빼면 강추입니다. 이렇게 추천해주신 분께 감사의 말씀을 드립니다.
그러고 나서 우분투를 ssd의 나머지 반에 설치하고, 스왑도 넉넉하게 (메모리도 4G라서 크게 필요할 것 같지는 않지만 그래도 혹 모르니 메모리의 2배 이상으로 해줬습니다. ), hdd에는 home을 설치하구요. 그런데 멀티부팅이 안되더군요. 정확히는 GRUB의 부팅 메뉴에 Windows 8.1이 안 나타나는 겁니다. Windows 8.1을 재설치해야되나 싶었는데, 간단하게 처리했습니다.
우분투로 부팅해서 sudo update-grub2를 실행합니다. (update-grub도 있는데 차이는 잘 모르겠습니다. 그냥 최신 버전이 나아도 낫겠죠. ^^; )
그럼 디스크에 설치되어 있는 OS들을 찾아줍니다. 이후에 sudo grub-mkconfig를 해줍니다. 그럼 자동으로 GRUB 메뉴를 만들어 줍니다. 정말 편해졌습니다. GRUB 메뉴 건들다가 잘못해서 재설치를 해야하거나 할 필요가 없어졌습니다. TT
그런데 Windows 8.1 메뉴가 맨 위에 있지는 않더군요. 순서가 어떻게 설정되는지는 모르겠습니다. grub 메뉴의 맨 위가 기본값으로 설정되어있는데, 그걸 바꾸고 싶으면 '/etc/default/grub'에 있는 'GRUB_DEFAULT=0'의 값을 바꿔주면 됩니다. 메뉴 맨위가 0, 그 다음부터는 1,2,... 이렇게 됩니다. 바꿔주고 나서 다시 'sudo grub-mkconfig'를 해줘야 적용됩니다.
요약:
- sudo update-grub2
- sudo grub-mkconfig (혹시 메뉴의 기본값을 바꾸고 싶으면)
- /etc/default/grub 에서 GRUB_DEFAULT=0 의 값을 1,2,3,...으로 수정 - sudo grub-mkconfig
대강의 구성은 intel i3, ssd + hdd 구요. ssd에 윈도우와 우분투를 같이 깔기로 했습니다.
파티션은 절반으로 나누고, 앞쪽에 Windows 8.1을 뒤쪽에 우분투 15.04를 깔았습니다.
우선 Windows 8.1를 깔았습니다. ssd라서 금방 깔리더군요. 부팅도 정말 빠릅니다. 읽고 쓰는데 횟수 제한이 있다는 것만 빼면 강추입니다. 이렇게 추천해주신 분께 감사의 말씀을 드립니다.
그러고 나서 우분투를 ssd의 나머지 반에 설치하고, 스왑도 넉넉하게 (메모리도 4G라서 크게 필요할 것 같지는 않지만 그래도 혹 모르니 메모리의 2배 이상으로 해줬습니다. ), hdd에는 home을 설치하구요. 그런데 멀티부팅이 안되더군요. 정확히는 GRUB의 부팅 메뉴에 Windows 8.1이 안 나타나는 겁니다. Windows 8.1을 재설치해야되나 싶었는데, 간단하게 처리했습니다.
우분투로 부팅해서 sudo update-grub2를 실행합니다. (update-grub도 있는데 차이는 잘 모르겠습니다. 그냥 최신 버전이 나아도 낫겠죠. ^^; )
그럼 디스크에 설치되어 있는 OS들을 찾아줍니다. 이후에 sudo grub-mkconfig를 해줍니다. 그럼 자동으로 GRUB 메뉴를 만들어 줍니다. 정말 편해졌습니다. GRUB 메뉴 건들다가 잘못해서 재설치를 해야하거나 할 필요가 없어졌습니다. TT
그런데 Windows 8.1 메뉴가 맨 위에 있지는 않더군요. 순서가 어떻게 설정되는지는 모르겠습니다. grub 메뉴의 맨 위가 기본값으로 설정되어있는데, 그걸 바꾸고 싶으면 '/etc/default/grub'에 있는 'GRUB_DEFAULT=0'의 값을 바꿔주면 됩니다. 메뉴 맨위가 0, 그 다음부터는 1,2,... 이렇게 됩니다. 바꿔주고 나서 다시 'sudo grub-mkconfig'를 해줘야 적용됩니다.
요약:
- sudo update-grub2
- sudo grub-mkconfig (혹시 메뉴의 기본값을 바꾸고 싶으면)
- /etc/default/grub 에서 GRUB_DEFAULT=0 의 값을 1,2,3,...으로 수정 - sudo grub-mkconfig
2014/05/30
객관적 판단이라는 헛소리
결론부터 내리면, 객관과 판단은 같이 붙여 쓸 수 없다.
사전적 의미로 객관은, '1. 자기와의 관계에서 벗어나 제삼자의 입장에서 사물을 보거나 생각함 2. 의지나 인식 등의 정신 작용이 향하는 대상. 또는 정신적, 육체적 자아와 독립하여 존재하는 외계의 사물 (다음 사전 참조)' 이라고 하는데, '객관적'이라는 대부분의 경우 사전적 의미의 <1. 자기와의 관계에서 벗어나 제삼자의 입장에서 사물을 보거나 생각함>을 사용하는 것 같다.
사전적 의미 2번의 <의지나 인식 등의 정신 작용이 향하는 대상. 또는 정신적, 육체적 자아와 독립하여 존재하는 외계의 사물>로서 판단한다는 말은, 판단을 할 수 있는 다른 존재가 판단한다는 것이므로 그것이 나의 판단이 될 수는 없다. 즉 2번의 의미로서 '객관적 판단'은 <다른 사람의 판단>이라는 말이 되므로, '누가 그랬다더라', 내지는 '누가 그렇게 판단한다더라' 정도의 <타인의 판단을 빌려오는> 것을 의미한다. 따라서 참조 이상의 의미는 가질 수 없다.
보통 사용하는 1번의 자기와의 관계에서 벗어나 제삼자의 입장에서 사물을 보거나 생각한다, 라는 건 사실상 불가능하다. 만일 이것이 가능하려면, 제삼자의 판단의 기초가 되는 지식과 경험을 내가 공유하고 있어야한다. 하지만 나 이외의 다른 누군가와 지식과 경험을 공유하는 것은 불가능하다. 만일 타인과의 지식과 경험을 공유하는 것이 가능하다면, 같은 수업을 듣고, 같은 시간을 향유하는 학생들의 성적은 일정할 것이다. 하지만 12년에 걸친 공공교육의 결과로 수많은 다른 지식과 경험을 가지는 학생들이 생겨나듯이, 다른 누군가와 지식과 경험을 공유하는 것은 불가능하다.
나의 주장의 기초는, 판단의 기준은 기존의 지식과 경험으로, 사람들은 자신의 한계 이상의 판단은 할 수 없다, 라는 가설에서 시작한다.
대부분의 사람들이 '객관적 판단'이라고 말할 때 의도하는 바는, <누가 생각하던 마찬가지>라는 것, <다른 사람도 그렇게 생각하니 나의 판단이 맞다> 라고 하는, 자신의 주장의 정당성을 제삼자로부터 빌려오고 싶을 때 쓰는 것 같다. 혹은 나의 이해관계와 무관하게 판단하고 있다, 라는 탈자아의 주장을 하고 싶을 때에도 쓰는 것으로 보인다.
판단의 기초가 되는 지식과 경험이 서로 다르므로, 그 결과로 생겨나는 판단 또한 자기만의 견해나 관점일 뿐이다.
따라서 모든 판단은 주관일 수 밖에 없다. '객관적 판단'이라는 말은 '객관적 주관'이라는 모순된 결과를 만들어 낼 뿐이다.
2014/04/08
구글 코드잼 기출문제
기출문제하니까, 자격증 시험 생각나네요. ㅋㅋ
https://code.google.com/codejam/contest/2924486/dashboard#s=p1
Small Input에서는 답이 맞는데, Large Input으로 가니 답이 틀리네요. 아마 변수 한계 때문에 생기는 문제같은데, 일단 Small Input을 맞추니 풀기가 싫어져서 일단 냅둬봅니다. 나중에라도 큰 값을 처리하는 방식에 익숙해지면 수정해야겠네요.
코드는
https://github.com/ptjoker95/Rational-Number-Tree
성적들 보니까,상위권은 단번에 맞추더군요. 한번이라도 오답을 내면 그만큼 패널티를 받는 것 같구요. 코딩스타일이 일단 한번 해보고 수정하는 스타일이라서 많이 연습을 해서 한번에 답을 내는 습관을 들여야 될 것 같네요.
https://code.google.com/codejam/contest/2924486/dashboard#s=p1
Small Input에서는 답이 맞는데, Large Input으로 가니 답이 틀리네요. 아마 변수 한계 때문에 생기는 문제같은데, 일단 Small Input을 맞추니 풀기가 싫어져서 일단 냅둬봅니다. 나중에라도 큰 값을 처리하는 방식에 익숙해지면 수정해야겠네요.
코드는
https://github.com/ptjoker95/Rational-Number-Tree
성적들 보니까,상위권은 단번에 맞추더군요. 한번이라도 오답을 내면 그만큼 패널티를 받는 것 같구요. 코딩스타일이 일단 한번 해보고 수정하는 스타일이라서 많이 연습을 해서 한번에 답을 내는 습관을 들여야 될 것 같네요.
2014/04/02
철저 토론 「혐한」 왜, 일본인은 그렇게 한국을 싫어하는가. 언급하기 어려운 「일본의 큰 문제」 제 3회. 2/6
( 출처의 허가없이 번역했습니다. 출처의 요구가 있을 경우에는 삭제합니다. )
( 安田(야스다), 小針(코하리), 辛(신) 3명의 대화 형식입니다. )
출처: http://gendai.ismedia.jp/articles/-/38462?page=2
코하리: 인터넷에서의 차별이나 편견이 늘어나고 있는 것은, 일본도 한국도 마찬가지입니다. 접속자수를 늘이기 위해 선정적인 반일기사를 게재하는 사이트는, 한국에도 많이 있습니다. 저는 한일 관계를 악화시키는 건, 정치가나 언론이라고 생각하고 있습니다. 한일 모두 국회의원은 표를 얻기 위해, 언론은 매출을 위해 「혐한」「반일」을 과격화시키고 있습니다. 그리고 그것이 국민들의 싸움에 기름을 붇고 있습니다.
특히 지금 일본의 언론은 한창 「혐한」상품을 내다 팔고 있습니다. 한국 대통령의 반일 행동 등을 등에 업고, 「혐한」이 넷우익뿐만이 아니라, 더 많은 국민들에게 받아들여지고 있습니다.
야스다: 하지만 한국에서 「반일」에 관한 책이 서점에 진열되거나 하지는 않잖아요.
신: 한국과 재일교포의 차별이, 유행처럼 가볍게 「소비」되고 있습니다. 하지만 「혐한」 그 자체가 특별히 새로운 현상은 아닙니다. 일본 사회는재일 한국·조선인이나, 한국·북한을 경시하는 차별의식을 계속 가지고 있었습니다.
코하리: 확실히 해두고 싶은 것이 있습니다만, 한국 혹은 북한이라고 하는 국가에 대한 정당한 이의를 가지는 것과, 재일한국·조선인에의 악질적인 민족차별과는 구별하지 않으면 안됩니다.
야스다: 일본에 재일교포가 있는 것은 한일합병의 결과로, 현재의 한국·북한과는 관계가 없습니다. 재일교포에의 차별은 일본 국내문제인데도, 왠지 한일문제, 북일문제라고 오해하고 있습니다.
신: 결국은 재일교포도 한국도 북한도, 일본인은 한데 뭉뚱그려서 「조선」으로 보고 있습니다.
「상대방이 싸움을 걸어왔다」
코하리: 국가로서의 한국을 비난하는 것 중에 하나는, 당연한 것도 있습니다. 예를 들어 노무현 정권은 06년 북한 미사일 실험에 대해 「굳이 일본처럼 새벽부터 야단법석을 떨 이유가 없다」(참고:http://www.yonhapnews.co.kr/bulletin/2009/04/05/0200000000AKR20090405076600043.HTML) 라고 성명을 발표했습니다. 이것이 한국정부에 강하게 항의해야할 사항이겠지요. (??? 우리가 쐈나 북한이 쐈지. 그리고 기사에도 나와있지만, 이 발표 후에 대북 지원을 끊었습니다. 뭐 실질적이라면 실질적인 제재겠지요. )
야스다: 예. 저도 정당한 비판이라면 얼마든지 해도 좋다고 생각합니다. 하지만 지금의 한국비판은, 민족차별과도 강하게 연결되어 있습니다. 자주 한국의 「반일」과 일본의 「혐한」이 대비되지만, 한국의 「반일」은 역사문제와 관련되어 있어, 「한국에서 일본인을 쫓아내자」라는 주장과는 연결되지 않습니다.
하지만 일본의 「혐한」은 한국·조선인을 사회로부터 추방하자고 하는 배외주의가되버렸습니다.저는,한국비난을 하기 전에, 일본 국내의 차별을 없애지 않으면 안된다고 생각하고 있습니다.
( 安田(야스다), 小針(코하리), 辛(신) 3명의 대화 형식입니다. )
출처: http://gendai.ismedia.jp/articles/-/38462?page=2
코하리: 인터넷에서의 차별이나 편견이 늘어나고 있는 것은, 일본도 한국도 마찬가지입니다. 접속자수를 늘이기 위해 선정적인 반일기사를 게재하는 사이트는, 한국에도 많이 있습니다. 저는 한일 관계를 악화시키는 건, 정치가나 언론이라고 생각하고 있습니다. 한일 모두 국회의원은 표를 얻기 위해, 언론은 매출을 위해 「혐한」「반일」을 과격화시키고 있습니다. 그리고 그것이 국민들의 싸움에 기름을 붇고 있습니다.
특히 지금 일본의 언론은 한창 「혐한」상품을 내다 팔고 있습니다. 한국 대통령의 반일 행동 등을 등에 업고, 「혐한」이 넷우익뿐만이 아니라, 더 많은 국민들에게 받아들여지고 있습니다.
야스다: 하지만 한국에서 「반일」에 관한 책이 서점에 진열되거나 하지는 않잖아요.
신: 한국과 재일교포의 차별이, 유행처럼 가볍게 「소비」되고 있습니다. 하지만 「혐한」 그 자체가 특별히 새로운 현상은 아닙니다. 일본 사회는재일 한국·조선인이나, 한국·북한을 경시하는 차별의식을 계속 가지고 있었습니다.
코하리: 확실히 해두고 싶은 것이 있습니다만, 한국 혹은 북한이라고 하는 국가에 대한 정당한 이의를 가지는 것과, 재일한국·조선인에의 악질적인 민족차별과는 구별하지 않으면 안됩니다.
야스다: 일본에 재일교포가 있는 것은 한일합병의 결과로, 현재의 한국·북한과는 관계가 없습니다. 재일교포에의 차별은 일본 국내문제인데도, 왠지 한일문제, 북일문제라고 오해하고 있습니다.
신: 결국은 재일교포도 한국도 북한도, 일본인은 한데 뭉뚱그려서 「조선」으로 보고 있습니다.
「상대방이 싸움을 걸어왔다」
코하리: 국가로서의 한국을 비난하는 것 중에 하나는, 당연한 것도 있습니다. 예를 들어 노무현 정권은 06년 북한 미사일 실험에 대해 「굳이 일본처럼 새벽부터 야단법석을 떨 이유가 없다」(참고:http://www.yonhapnews.co.kr/bulletin/2009/04/05/0200000000AKR20090405076600043.HTML) 라고 성명을 발표했습니다. 이것이 한국정부에 강하게 항의해야할 사항이겠지요. (??? 우리가 쐈나 북한이 쐈지. 그리고 기사에도 나와있지만, 이 발표 후에 대북 지원을 끊었습니다. 뭐 실질적이라면 실질적인 제재겠지요. )
야스다: 예. 저도 정당한 비판이라면 얼마든지 해도 좋다고 생각합니다. 하지만 지금의 한국비판은, 민족차별과도 강하게 연결되어 있습니다. 자주 한국의 「반일」과 일본의 「혐한」이 대비되지만, 한국의 「반일」은 역사문제와 관련되어 있어, 「한국에서 일본인을 쫓아내자」라는 주장과는 연결되지 않습니다.
하지만 일본의 「혐한」은 한국·조선인을 사회로부터 추방하자고 하는 배외주의가되버렸습니다.저는,한국비난을 하기 전에, 일본 국내의 차별을 없애지 않으면 안된다고 생각하고 있습니다.
2014/03/27
CUDA OddEvenSorting문제점 발생
http://ptjoker95.blogspot.kr/2014/03/cuda-sorting-oddevensorting.html
뭐 알고리즘도 맞고, 결과도 대강맞는 것 같아서 냅두고 다음 정렬로 넘어가려고 잠깐 봤는데, 결과가 이상하게 나오는 겁니다. ㅋㅋㅋ
정렬이 잘 되다가 중간에 잘리고 다른 결과가 나옵니다. 예를 들면,
0 0 0 0 0 1 2 2 2 2 2 ... 495 495 495 496 0 0 0 0 01 1 1 1 1 ...
이런식으로요. 그래서 알고리즘 상에 문제가 있는 줄 알고 뚫어지게 봐도 이상은 없구요. 그래서 혹시나 해서 데이터를 줄여보니, 되더군요. 정확히는 4095 개가 한계이구, 그것보다 커지면 여지없이 잘못된 결과가 나옵니다.
CUDA 강의 중에 작업 순서에 관한 설명이 나오더니 이건가 봅니다.
그러니까 GPU가 돌아갈 때 모든 데이터를 한꺼번에 처리하는 게 아니고, 블럭별로 몇개 블럭씩 (제 경우에는 블럭 사이즈가 512이니까, 4개씩) 처리한다고 하던데, 그래서 문제가 발생한 것 같습니다. ㅋㅋ
물리적 한계라는 게 이런거로군요.
뭐 알고리즘도 맞고, 결과도 대강맞는 것 같아서 냅두고 다음 정렬로 넘어가려고 잠깐 봤는데, 결과가 이상하게 나오는 겁니다. ㅋㅋㅋ
정렬이 잘 되다가 중간에 잘리고 다른 결과가 나옵니다. 예를 들면,
0 0 0 0 0 1 2 2 2 2 2 ... 495 495 495 496 0 0 0 0 01 1 1 1 1 ...
이런식으로요. 그래서 알고리즘 상에 문제가 있는 줄 알고 뚫어지게 봐도 이상은 없구요. 그래서 혹시나 해서 데이터를 줄여보니, 되더군요. 정확히는 4095 개가 한계이구, 그것보다 커지면 여지없이 잘못된 결과가 나옵니다.
CUDA 강의 중에 작업 순서에 관한 설명이 나오더니 이건가 봅니다.
그러니까 GPU가 돌아갈 때 모든 데이터를 한꺼번에 처리하는 게 아니고, 블럭별로 몇개 블럭씩 (제 경우에는 블럭 사이즈가 512이니까, 4개씩) 처리한다고 하던데, 그래서 문제가 발생한 것 같습니다. ㅋㅋ
물리적 한계라는 게 이런거로군요.
2014/03/26
OpenGL 공부를 시작했습니다.
뭐 이것저것 뜬금없이 튜토리얼만 계속 해보는 중입니다. ㅋㅋ
http://www.extremetech.com/gaming/179010-who-needs-directx-amd-nvidia-and-intel-team-up-demonstrate-ultra-low-overhead-opengl
뭐가 어떻게 돌아가는 지는 잘 모르겠지만, 대강 이해하기로는,
- GPU 제조회사들간에 API를 각각 만들다가, (예를 들면, NVidia의 CUDA나 Tegra처럼)
- 그럼 너무 비용이 많이 들어가니 OpenGL로 통일하자.
라는 것 같은데요. 그래서 일단 OpenGL이 뭔지나 알고 넘어가자, 싶어서 튜토리얼을 펼쳐봤습니다.
(사족이지만, OpenCL도 있고 뭐 이것저것 많은 것 같습니다. 중요한건, 병렬 컴퓨팅을 이용한다는 거겠죠. 뭐 나중에 다 통합될 수도 있지 않을까 싶습니다만. 근데 OpenCL은 너무 어렵더군요. --;;)
http://openglbook.com/the-book/chapter-1-getting-started/
그냥 있는 코드 그대로 갖다 붙였습니다. 컴파일할 때의 플래그는 "-lglut -lGLU -lGL -lX11 -lm"을 붙이면 어찌어찌 됩니다. ㅋ Eclipse에서는 Cross G++ Linker에 있는 Libraries 세팅에 넣어줘야 됩니다.(앞의 '-l' 빼구요)
그런데 안되는 겁니다. 다른 예 ( http://ogldev.atspace.co.uk/index.html)는 그냥 잘 되서 참 좋아하던 참인데요. --;;
그래서 이것저것 뒤져보던 참에 알게 된 것 중에 하나는 xorg.init파일을 수정하라는 거였는데요. 제 경우에는 그것 때문만은 아닌 것 같구요. 예제 중에
glutInitContextVersion( int, int )
이라는 함수가 사용되는데요. OpenCL버전을 넣는 함수인것 같습니다. 앞의 숫자는 major버전, 뒤의 숫자는 minor버전인데요. 저의 경우에는 3.3버전을 쓰고 있었는데, 튜토리얼에 있는 그대로 4랑 0을 넣었더니 resource가 안 맞는다면서 에러가 나더군요. 저 숫자를 설치되어 있는 버전인 (3,3)으로 바꾸니 제대로 구동하더군요.
http://www.extremetech.com/gaming/179010-who-needs-directx-amd-nvidia-and-intel-team-up-demonstrate-ultra-low-overhead-opengl
뭐가 어떻게 돌아가는 지는 잘 모르겠지만, 대강 이해하기로는,
- GPU 제조회사들간에 API를 각각 만들다가, (예를 들면, NVidia의 CUDA나 Tegra처럼)
- 그럼 너무 비용이 많이 들어가니 OpenGL로 통일하자.
라는 것 같은데요. 그래서 일단 OpenGL이 뭔지나 알고 넘어가자, 싶어서 튜토리얼을 펼쳐봤습니다.
(사족이지만, OpenCL도 있고 뭐 이것저것 많은 것 같습니다. 중요한건, 병렬 컴퓨팅을 이용한다는 거겠죠. 뭐 나중에 다 통합될 수도 있지 않을까 싶습니다만. 근데 OpenCL은 너무 어렵더군요. --;;)
http://openglbook.com/the-book/chapter-1-getting-started/
그냥 있는 코드 그대로 갖다 붙였습니다. 컴파일할 때의 플래그는 "-lglut -lGLU -lGL -lX11 -lm"을 붙이면 어찌어찌 됩니다. ㅋ Eclipse에서는 Cross G++ Linker에 있는 Libraries 세팅에 넣어줘야 됩니다.(앞의 '-l' 빼구요)
그런데 안되는 겁니다. 다른 예 ( http://ogldev.atspace.co.uk/index.html)는 그냥 잘 되서 참 좋아하던 참인데요. --;;
그래서 이것저것 뒤져보던 참에 알게 된 것 중에 하나는 xorg.init파일을 수정하라는 거였는데요. 제 경우에는 그것 때문만은 아닌 것 같구요. 예제 중에
glutInitContextVersion( int, int )
이라는 함수가 사용되는데요. OpenCL버전을 넣는 함수인것 같습니다. 앞의 숫자는 major버전, 뒤의 숫자는 minor버전인데요. 저의 경우에는 3.3버전을 쓰고 있었는데, 튜토리얼에 있는 그대로 4랑 0을 넣었더니 resource가 안 맞는다면서 에러가 나더군요. 저 숫자를 설치되어 있는 버전인 (3,3)으로 바꾸니 제대로 구동하더군요.
2014/03/25
최소로 색칠하기, Coloring in Discrete Optimization
https://class.coursera.org/optimization-002 에서 나온 문제입니다.
Node 들이 있고, 각 Node는 Edge에 의해 다른 Node와 연결되어 있습니다.
Node에 색을 칠하는 데, 제한조건은 Edge로 연결되어 있는 바로 옆 Node와 색이 같아서는 안 됩니다.
목표는 최소한의 색으로 Node들을 칠하는 것입니다.
제 알고리즘은
- Node 중 Edge의 수가 가장 작은 Node부터 색을 칠합니다.
- 색을 칠할 때에는 연결되어 있는 Node에 칠해져있는 색을 알아봅니다.
- 색의 가지수는 많아봐야 Node 숫자보다는 작으므로, 0부터 최대치(Node의 갯수)까지 넣어보는 데, 연결되어 있는 Node에 그 숫자가 없으면 일단 그 Node에 가장 낮은 수를 넣습니다.
결과는 썩 좋은 편은 아닙니다. ㅋㅋㅋ 계속 개선해나가야죠.
Node 들이 있고, 각 Node는 Edge에 의해 다른 Node와 연결되어 있습니다.
Node에 색을 칠하는 데, 제한조건은 Edge로 연결되어 있는 바로 옆 Node와 색이 같아서는 안 됩니다.
목표는 최소한의 색으로 Node들을 칠하는 것입니다.
제 알고리즘은
- Node 중 Edge의 수가 가장 작은 Node부터 색을 칠합니다.
- 색을 칠할 때에는 연결되어 있는 Node에 칠해져있는 색을 알아봅니다.
- 색의 가지수는 많아봐야 Node 숫자보다는 작으므로, 0부터 최대치(Node의 갯수)까지 넣어보는 데, 연결되어 있는 Node에 그 숫자가 없으면 일단 그 Node에 가장 낮은 수를 넣습니다.
결과는 썩 좋은 편은 아닙니다. ㅋㅋㅋ 계속 개선해나가야죠.
def ConnectedNodes( SelectedNode, edges ):
# 연결되어 있는 노드를 담을 리스트
ConnectedNodes = []
# edge를 죽 훑어본다.
for edge in edges:
if SelectedNode in edge:
temp = list(edge)
temp.remove(SelectedNode)
tempint = int(temp[0])
ConnectedNodes.append(tempint)
return ConnectedNodes
def ColoringNode( index, edges, solution, node_count, Color ):
#연결되어있는 node의 리스트 생성
CNodes = ConnectedNodes( index, edges )
#연결되어 있는 node의 색깔을 받는다.
CNColors = []
for cn in CNodes:
CNColors.append(solution[cn])
#0부터 node의 숫자만큼의 색깔 중에서 가장 낮은 숫자를 칠한다.
for i in range(0, node_count):
if not i in CNColors:
solution[index] = i
return
solution[index] = Color
return
def solve_it(input_data):
# Modify this code to run your optimization algorithm
# parse the input
lines = input_data.split('\n')
first_line = lines[0].split()
node_count = int(first_line[0])
edge_count = int(first_line[1])
edges = []
for i in range(1, edge_count + 1):
line = lines[i]
parts = line.split()
edges.append((int(parts[0]), int(parts[1])))
solution = [-1]*node_count
# 각 node별로 edge들의 갯수를 구한다.
NodesHaveEdgenum = [0]*node_count
for edge in edges:
NodesHaveEdgenum[edge[0]] += 1
NodesHaveEdgenum[edge[1]] += 1
# 각 node별로 edge의 수가 적은 순으로 사전 정렬
WeightedIndex = []
for i in range(0, node_count):
WeightedIndex.append( [i,NodesHaveEdgenum[i]] )
WeightedIndex = sorted( WeightedIndex, key=lambda WeightedIndex:WeightedIndex[1], reverse=False )
#사전 정렬 끝.
#계산이 끝난 후 solution에서 각각 1을 빼야됨
#많아봐야 노드 갯수 이상의 색을 칠할 필요는 없으므로 loop의 한계는 node수로 한계지어놓는다.
for i, index in enumerate(WeightedIndex):
#node의 index를 주면 해당 node에 가장 작은 색을 칠한다.
#print "index[0]: ", index[0], " ,edges: ", edges, " ,solution: ", solution, " ,i: ", i
ColoringNode( index[0], edges, solution, node_count, i )
# prepare the solution in the specified output format
output_data = str(node_count) + ' ' + str(0) + '\n'
output_data += ' '.join(map(str, solution))
return output_data
import sys
if __name__ == '__main__':
if len(sys.argv) > 1:
file_location = sys.argv[1].strip()
input_data_file = open(file_location, 'r')
input_data = ''.join(input_data_file.readlines())
input_data_file.close()
print solve_it(input_data)
else:
print 'This test requires an input file. Please select one from the data directory. (i.e. python solver.py ./data/gc_4_1)'
2014/03/20
CUDA sorting. OddEvenSorting. 병렬 홀짝 정렬
이전에 하던 sorting은 제겐 너무 어렵더군요. --;; 그래서 일단 가장 기초부터 해봤습니다.
이름하야, Odd Even Sorting입니다. 처음에는 홀수(혹은 짝수) 자리에 있는 것과 바로 다음 것을 비교해서 정렬하구요. 그 다음 스텝에는 짝수(혹은 홀수) 자리에 있는 것과 바로 다음 것을 비교 정렬합니다. 그리고 이걸 N(자료크기)번 반복하면 됩니다. 코딩도 매우 간단합니다. 다만, 정렬 시간이 N이 걸리고, GPU에서의 N은 CPU의 N보다 더 오래 걸린다는 점이 단점입니다.
좋은 알고리즘으로하면 log(N)이나 log(N)^2 정도 걸린다는데요. --;; 좋은 알고리즘은 제 머리로는 이해가 어렵다는....
알고리즘은 http://www.dcc.fc.up.pt/~fds/aulas/PPD/1112/sorting.pdf 을 참조했습니다.
코딩이나 개념자체는 쉽습니다.
그리고 참고로 제 PC로 기동했을 때 자료값을 10만개 주면 돌아는 가는데, 이상한 값들이 튀어나오더군요. 문제가 뭔지는 차차 알게되겠죠. 일단은 여기까지.
이름하야, Odd Even Sorting입니다. 처음에는 홀수(혹은 짝수) 자리에 있는 것과 바로 다음 것을 비교해서 정렬하구요. 그 다음 스텝에는 짝수(혹은 홀수) 자리에 있는 것과 바로 다음 것을 비교 정렬합니다. 그리고 이걸 N(자료크기)번 반복하면 됩니다. 코딩도 매우 간단합니다. 다만, 정렬 시간이 N이 걸리고, GPU에서의 N은 CPU의 N보다 더 오래 걸린다는 점이 단점입니다.
좋은 알고리즘으로하면 log(N)이나 log(N)^2 정도 걸린다는데요. --;; 좋은 알고리즘은 제 머리로는 이해가 어렵다는....
알고리즘은 http://www.dcc.fc.up.pt/~fds/aulas/PPD/1112/sorting.pdf 을 참조했습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
#include <iostream>
#include <cuda.h>
#include <time.h>
#include <math.h>
using namespace std;
// 테스트 용이므로 일단 자료 크기는 10000으로
// 1D이니까 그냥 블럭사이즈는 512로
//10만개부터 에러났음. 아마 랜덤 숫자 만들어내는 데, 아니면 GPU메모리 상에서 문제가 발생한 것 같음.
// 만일 화면 데이터를 정렬한다고 하면, 2560x1600 = 4,096,000 픽셀이니까 GPU메모리 상에서의 문제가
// 아니라 랜덤 숫자 만들어내는 곳에서 문제가 발생한 것일 수도...
#define DATASIZE 10000
#define BLOCK_SIZE 512
__global__ void oddevensort ( int * input, int * output, unsigned int len )
{
//개별 블럭의 좌표
unsigned int tx = threadIdx.x;
//전체 이미지의 좌표
unsigned int x = tx + blockDim.x * blockIdx.x;
//이동에 쓸 임시 변수
int temp;
//자료의 길이만큼 돌리는데, 인덱스(i)가 짝수이면 데이터의 짝수자리와 그 다음 숫자를 비교.
//인덱스가 홀수이면 데이터의 홀수자리와 그 다음 숫자를 비교해서 정렬한다.
for( int i=0; i<len; i++)
{
if( i % 2 == 0 )
{
// 길이를 측정안해주면 블럭에 남아있던 자리에 있는 자료가 튀어나올 수 있으니 조심.
if( input[x] > input[x+1] && x < len && x % 2 == 0)
{
temp = input[x+1];
input[x+1] = input[x];
input[x] = temp;
}
}
else
{
if( input[x] > input[x+1] && x < len && x % 2 != 0)
{
temp = input[x+1];
input[x+1] = input[x];
input[x] = temp;
}
}
}
output[x] = input[x];
__syncthreads();
}
int main()
{
// 테스트에 쓸 숫자 생성
int TestInput[DATASIZE], TestOutput[DATASIZE];
srand(time(NULL));
for( int i = 0; i < DATASIZE; i++ )
{
TestInput[i] = rand() % 500;
}
//device 설정
int *devInput, *devOutput;
//일단 크기는 아니까
unsigned int MemDataSize = DATASIZE * sizeof(float);
// device 자리 잡아주고
cudaMalloc((void**)&devInput, MemDataSize );
cudaMalloc((void**)&devOutput, MemDataSize );
cudaMemset( devOutput, 0, MemDataSize );
// 자리 잡았으면 복사
cudaMemcpy( devInput, TestInput, MemDataSize, cudaMemcpyHostToDevice);
// block 크기 설정
// 1D 이니까, 그냥 간단하게...
dim3 dimBlocksize( BLOCK_SIZE );
dim3 dimGridsize( ceil((DATASIZE-1)/(float)BLOCK_SIZE) + 1 );
// 일단 Max값과 min값을 알아내야됨.
// 처음부터 끝까지 휙 둘러보면 되니 이건 CPU에게 맡김.
oddevensort<<< dimGridsize, dimBlocksize >>>( devInput, devOutput, DATASIZE );
// 결과물 복사
cudaMemcpy( TestOutput, devOutput, MemDataSize, cudaMemcpyDeviceToHost);
for( int i=0; i<DATASIZE; i++ )
{
cout << TestOutput[i] << ", ";
if( (i+1)%10 == 0 )
{
cout << endl;
}
}
// 위에 GPU에 마련한 자리 해소. 그때 그때 해놓는 게 편할 듯
cudaFree( devInput );
cudaFree( devOutput );
return 0;
}
|
코딩이나 개념자체는 쉽습니다.
그리고 참고로 제 PC로 기동했을 때 자료값을 10만개 주면 돌아는 가는데, 이상한 값들이 튀어나오더군요. 문제가 뭔지는 차차 알게되겠죠. 일단은 여기까지.
2014/03/18
지진 분석
지진 데이터는 있는데, 지진이 어디서 언제 어떻게 일어날 지 알 수는 없을까? 라는 의문이 들어서 찾아봤습니다.
일단은 위키피디아에서 시작하면 되겠네요.
http://en.wikipedia.org/wiki/Earthquake_prediction
참조목록이 넘쳐나네요. --;;
일단은 위키피디아에서 시작하면 되겠네요.
http://en.wikipedia.org/wiki/Earthquake_prediction
참조목록이 넘쳐나네요. --;;
2014/03/11
2014/03/10
GPU로 sorting 해보기 step 2
방금 step 2를 올렸는데, 인덱스 상에 안 들어갈 정도로 큰 수를 날려버리는 버그가 있어서 급히 잡았습니다. ㅋㅋ
정렬할 데이터 중에 유난히 큰 수가 있으면 stepWidth가 너무 커지고, 그러다보면 슬라이스 하나의 크기 중에 GPU 블럭보다 큰 게 생길 수 있을 것 같아서, 크기를 조정하는 코드를 새로 넣었습니다.
간단히 설명하면 블럭보다 슬라이스의 크기들이 작아질 때까지 stepWidth를 조정해서 슬라이스의 크기를 조정하게 됩니다. sorting 들어가기 전의 전처리도 꽤나 신경이 많이 쓰이는 군요. ㅋㅋ
기존의 코드에는 없던 SliceLength를 만들어서, 슬라이스들의 총 크기를 알 수 있도록 했습니다. 그래서 GPU 커널에서 슬라이스 인덱스 처리 중에 너무 큰 수가 나올 경우, 가장 마지막 슬라이스에 그 수를 넣도록 했습니다. 어차피 커서 문제일테니 맨 마지막 슬라이스에 넣도록 하는 게 맞겠죠.
for의 조건문을 이용해서, 슬라이스 중 크기가 가장 큰 것이 GPU 블럭보다 작으면 그냥 for문을 패스하도록 했습니다. 처음에는 if를 넣어서 분기했었는데, 굳이 필요없겠더군요.
안전을 위해서 stepWidth가 50보다 작아지면 프로그램을 종료하도록 했습니다. 최악의 경우에는 슬라이스 크기가 1나 2개 정도로 될 수도 있겠더군요.
다음에는 나뉘어진 Slice를 Bucket에 넣는 작업입니다. Bucket의 크기는 GPU의 블럭 크기와 동일하며, 하나의 Bucket에 크기를 넘지 않는 범위내에서 가장 많은 Slice를 넣어야 좀 더 효율적일 것 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
// AN EFFICIENT SORTING ALGORITHM WITH CUDA
//(http://www.researchgate.net/publication/228848208_An_efficient_sorting_algorithm_with_CUDA/file/9c96052307d2a1add4.pdf) 참조
// Shifu Chen, Jing Qin, Yongming Xie, Junping Zhao, and Pheng-Ann Heng
//Optimizing Parallel Reductiuon 참조
// http://developer.download.nvidia.com/assets/cuda/files/reduction.pdf
#include <iostream>
#include <fstream>
#include <cuda.h>
#include <time.h>
#include <math.h>
using namespace std;
// 테스트 용이므로 일단 자료 크기는 1000으로
// 1D이니까 그냥 블럭사이즈는 512로
// EP는 슬라이스의 사이즈
#define DATASIZE 1000
#define BLOCK_SIZE 512
#define EP 256
__global__ void SliceDivision ( float * input, float minValue, unsigned int stepWidth, unsigned int DataSize, unsigned int * SliceOfElements, unsigned int * SliceSizes, unsigned int * OffsetInSlice, unsigned int SliceLength )
{
//개별 블럭의 좌표
unsigned int tx = threadIdx.x;
//전체 이미지의 좌표
unsigned int x = tx + blockDim.x * blockIdx.x;
// sliceIndex: 어떤 슬라이스에 들어가는 지 필요한 인덱스
// offset: 각 슬라이스 안에서의 offset
unsigned int sliceIndex, offset;
//ceil을 쓰게 되면 sliceIndex[0]에 들어가는 건 가장 작은 숫자밖에 없음. 그래서 floor를 씀
//unsigned int를 쓰기 때문에 음수가 안 나오도록 주의.
if( x < DataSize )
{
sliceIndex = (unsigned int)(floor(( input[x] - minValue ) / stepWidth));
//sliceIndex가 슬라이스들의 크기보다 크면 가장 큰 곳에 넣음
if( sliceIndex > SliceLength-1 )
sliceIndex = SliceLength-1;
offset = atomicAdd( &SliceSizes[sliceIndex], 1 );
SliceOfElements[x] = sliceIndex;
OffsetInSlice[x] = offset;
}
}
int main()
{
// 테스트에 쓸 숫자 생성
float TestInput[DATASIZE], TestOutput[DATASIZE];
unsigned int MaxSliceSize, SliceLength;
srand(time(NULL));
// slice 크기 조정하는 코드 확인하기 위해서 맨 마지막 자리에 꽤 큰 숫자를 넣어보겠습니다.
for( int i = 0; i < DATASIZE-2; i++ )
{
TestInput[i] = rand() % DATASIZE;
}
TestInput[DATASIZE-1] = 10000;
//device 설정
float *devInput, *devOutput;
float MaxValue, minValue;
//일단 크기는 아니까
unsigned int MemDataSize = DATASIZE * sizeof(float);
// device 자리 잡아주고
cudaMalloc((void**)&devInput, MemDataSize );
cudaMalloc((void**)&devOutput, MemDataSize );
// 자리 잡았으면 복사
cudaMemcpy( devInput, TestInput, MemDataSize, cudaMemcpyHostToDevice);
// block 크기 설정
// 1D 이니까, 그냥 간단하게...
dim3 dimBlocksize( BLOCK_SIZE );
dim3 dimGridsize( ceil((DATASIZE-1)/(float)BLOCK_SIZE) + 1 );
// 일단 Max값과 min값을 알아내야됨.
// 처음부터 끝까지 휙 둘러보면 되니 이건 CPU에게 맡김.
MaxValue = TestInput[0];
minValue = TestInput[0];
for( int i=1; i < DATASIZE; i++ )
{
if( MaxValue < TestInput[i] )
MaxValue = TestInput[i];
if( minValue > TestInput[i] )
minValue = TestInput[i];
}
// stepWidth 계산
unsigned int stepWidth = (unsigned int)(ceil((MaxValue - minValue) * (float)EP / (float)DATASIZE));
// sliceSizes: 각 슬라이스의 크기를 넣는 array. 전체 크기를 슬라이스의 크기로 나눈 ceil값
unsigned int *SliceSizes, *devSliceSizes;
SliceLength = (unsigned int)( ceil(DATASIZE / (float)stepWidth ));
cout << "SliceLength: " << SliceLength << endl;
SliceSizes = new (nothrow) unsigned int[ SliceLength ];
cudaMalloc((void**)&devSliceSizes, (unsigned int)(SliceLength * sizeof(unsigned int)) );
cudaMemset(devSliceSizes, 0, SliceLength * sizeof(unsigned int) );
// sliceOfElements: 각 값들의 슬라이스 인덱스 값
unsigned int SliceOfElements[DATASIZE], *devSliceOfElements;
cudaMalloc((void**)&devSliceOfElements, DATASIZE * sizeof(unsigned int) );
cudaMemset(devSliceOfElements, 0, DATASIZE * sizeof(unsigned int) );
// offsetInSlice: 슬라이스 안에서의 offset 값
unsigned int OffsetInSlice[DATASIZE], *devOffsetInSlice;
cudaMalloc((void**)&devOffsetInSlice, DATASIZE * sizeof(unsigned int) );
cudaMemset(devOffsetInSlice, 0, DATASIZE * sizeof(unsigned int) );
// sliceOffsets: 각 값들의 전체 자료에서 offset 값
// unsigned int sliceOffsets[DATASIZE], *devsliceOffsets;
// cudaMalloc((void**)&devsliceOffsets, DATASIZE * sizeof(unsigned int) );
SliceDivision<<< dimGridsize, dimBlocksize >>>( devInput, minValue, stepWidth, DATASIZE, devSliceOfElements, devSliceSizes, devOffsetInSlice, SliceLength );
// 결과물 복사
cudaMemcpy( TestOutput, devOutput, MemDataSize, cudaMemcpyDeviceToHost);
cudaMemcpy( SliceSizes, devSliceSizes, ceil(DATASIZE / (float)stepWidth ) * sizeof(unsigned int), cudaMemcpyDeviceToHost);
cudaMemcpy( OffsetInSlice, devOffsetInSlice, DATASIZE * sizeof(unsigned int), cudaMemcpyDeviceToHost);
cudaMemcpy( SliceOfElements, devSliceOfElements, DATASIZE * sizeof(unsigned int), cudaMemcpyDeviceToHost);
MaxSliceSize = SliceSizes[0];
for( int i = 1; i < (unsigned int)( ceil(DATASIZE / (float)stepWidth )); i++)
{
//슬라이스 중에 가장 큰 크기를 MaxSliceSize에 넣음
if( MaxSliceSize < SliceSizes[i] )
{
MaxSliceSize = SliceSizes[i];
}
}
//슬라이스 중에 가장 큰 크기가 BLOCK_SIZE보다 클 경우에는 stepWidth를 조정해서 다시 계산.
// 이 때, sliceSize를 가지는 array의 크기가 달라질 테니 그것도 같이 조정
// 일단 한번 크면 또 클 수도 있으니 루프를 써서 일정 크기로 줄어들게 함. 일단은 64개 씩
//크기가 1보다 같거나 작을 때까지 돌림. 너무 작아지면 일단은 프로그램 정지
for( unsigned int i = 1; MaxSliceSize > 512; i++ )
{
cout << "Max: " << MaxValue << ", min: " << minValue << ", stepWidth: " << stepWidth << ", MaxSliceSize: " << MaxSliceSize << ", i:" << i << endl;
//stepWidth 조정
stepWidth = (unsigned int)(ceil((MaxValue - minValue) * (float)EP / ((float)(DATASIZE * 2 * i ))));
SliceLength = (unsigned int)( ceil(DATASIZE / (float)stepWidth ));
cout << "SliceLength: " << SliceLength << endl;
// 기존의 슬라이스 크기를 넣은 array 삭제
delete[] SliceSizes;
// 슬라이스 크기를 넣는 array 다시 만들기
SliceSizes = new (nothrow) unsigned int[ SliceLength ];
// GPU 메모리도 삭제
cudaFree( devSliceSizes );
// GPU 메모리도 다시 만들고
cudaMalloc((void**)&devSliceSizes, (unsigned int)(SliceLength * sizeof(unsigned int)) );
// GPU 메모리 청소
cudaMemset(devSliceSizes, 0, (unsigned int)(SliceLength * sizeof(unsigned int)) );
//커널 다시 실행
SliceDivision<<< dimGridsize, dimBlocksize >>>( devInput, minValue, stepWidth, DATASIZE, devSliceOfElements, devSliceSizes, devOffsetInSlice, SliceLength );
// 결과물 복사
cudaMemcpy( TestOutput, devOutput, MemDataSize, cudaMemcpyDeviceToHost);
cudaMemcpy( SliceSizes, devSliceSizes, (unsigned int)(ceil(DATASIZE / (float)stepWidth ) * sizeof(unsigned int)), cudaMemcpyDeviceToHost);
cudaMemcpy( OffsetInSlice, devOffsetInSlice, DATASIZE * sizeof(unsigned int), cudaMemcpyDeviceToHost);
cudaMemcpy( SliceOfElements, devSliceOfElements, DATASIZE * sizeof(unsigned int), cudaMemcpyDeviceToHost);
// 슬라이스 크기가 BLOCK_SIZE보다 작은지 다시 확인
MaxSliceSize = SliceSizes[0];
for( int i = 1; i < (unsigned int)( ceil(DATASIZE / (float)stepWidth )); i++)
{
//슬라이스 중에 가장 큰 크기를 MaxSliceSize에 넣음
if( MaxSliceSize < SliceSizes[i] )
{
MaxSliceSize = SliceSizes[i];
}
}
//stepWidth 가 50보다 작으면 뭔가가 문제있는 걸로 판단하고 일단 계산 스톱. 잘못하면 무한 루프 걸림
if( stepWidth < 50 )
return 1;
}
cout << "Max: " << MaxValue << ", min: " << minValue << ", stepWidth: " << stepWidth << ", MaxSliceSize: " << MaxSliceSize << endl;
cout << "Max: " << MaxValue << ", min: " << minValue << endl;
for( int i = 0; i < (unsigned int)( ceil(DATASIZE / (float)stepWidth )); i++)
{
cout << i << "th sliceSizes: " << SliceSizes[i] << endl;
}
// 위에 GPU에 마련한 자리 해소. 그때 그때 해놓는 게 편할 듯
cudaFree( devInput );
cudaFree( devOutput );
cudaFree( devSliceSizes );
cudaFree( devSliceOfElements );
cudaFree( devOffsetInSlice );
// cudaFree( devsliceOffsets );
delete SliceSizes;
return 0;
}
|
정렬할 데이터 중에 유난히 큰 수가 있으면 stepWidth가 너무 커지고, 그러다보면 슬라이스 하나의 크기 중에 GPU 블럭보다 큰 게 생길 수 있을 것 같아서, 크기를 조정하는 코드를 새로 넣었습니다.
간단히 설명하면 블럭보다 슬라이스의 크기들이 작아질 때까지 stepWidth를 조정해서 슬라이스의 크기를 조정하게 됩니다. sorting 들어가기 전의 전처리도 꽤나 신경이 많이 쓰이는 군요. ㅋㅋ
기존의 코드에는 없던 SliceLength를 만들어서, 슬라이스들의 총 크기를 알 수 있도록 했습니다. 그래서 GPU 커널에서 슬라이스 인덱스 처리 중에 너무 큰 수가 나올 경우, 가장 마지막 슬라이스에 그 수를 넣도록 했습니다. 어차피 커서 문제일테니 맨 마지막 슬라이스에 넣도록 하는 게 맞겠죠.
for의 조건문을 이용해서, 슬라이스 중 크기가 가장 큰 것이 GPU 블럭보다 작으면 그냥 for문을 패스하도록 했습니다. 처음에는 if를 넣어서 분기했었는데, 굳이 필요없겠더군요.
안전을 위해서 stepWidth가 50보다 작아지면 프로그램을 종료하도록 했습니다. 최악의 경우에는 슬라이스 크기가 1나 2개 정도로 될 수도 있겠더군요.
다음에는 나뉘어진 Slice를 Bucket에 넣는 작업입니다. Bucket의 크기는 GPU의 블럭 크기와 동일하며, 하나의 Bucket에 크기를 넘지 않는 범위내에서 가장 많은 Slice를 넣어야 좀 더 효율적일 것 같습니다.
피드 구독하기:
글 (Atom)



