안녕하세요?
여러분의 많은 조언에 힘입어 여러가지 테스트를 진행중이나 아직 소득이 없는 오징어입니다.
간략한 상황은,
서버에서 연구 목적의 스크립트를 돌리는데 유독 서버에서만 엄청나게 느리게 돌아갑니다.
여러 코어로 돌려도 거의 노트북 싱글코어 수준이고, 제온 데스크탑보다 무지하게 느리네요.
1. 우선, I/O에서 병목이 있는지 확인해 보았어요. iotop으로.
예상했던 바와 같이 iotop은 거의 0에 수렴하는 값을 보였습니다. 바깥 루프 한 바퀴에 데이터를 한 번씩 읽는데,
한번 읽은 데이터를 (예를들어) 60개의 task로 나누어서 병렬처리 합니다. 이거 60개 처리하는데 시간이 말도 안되게 오래 걸리는 중이고요.
어쨌든 루프 처음에 데이터 읽을때 빼고는 I/O는 관련 없어 보여요.
2. shared numpy array를 각각 프로세스에서 자주 접근하면 서로 순서 기다리느라 느려진다는 말씀에 따라 수정을 조금 했습니다.
원래는 worker가 부르는 함수 안에서 shared array를 수십번 접근 했는데, 처음에 한번만 접근해서 필요한 부분 (그때그때 다르고 프로세스끼리 데이터가 안 겹친다는 보장도 없을 뿐더러 전체 데이터를 다 쓰지도 않아서 worker가 직접 잘라가도록 하는 수 밖에 없더라고요.. 예를 들면 대한민국 지도만한 데이터에서 시 이상만 쓰고 군은 버리는 식입니다.) 그렇게 worker가 잘라가도록 바꾸고, 그 이후로는 전체 shared array에 접근하지 않습니다.
(numpy array를 인덱스로 골라냈으니 메모리가 복사된 걸로 알고 있습니다. ind = np.array([1,3,5,7,9,10,11]) 일 때, sub_data = shared_arr[ind] 식으로.. 맞나요?)
하지만 속도가 눈에 띄게 바뀌지는 않았어요. 왠지 빨리진 것 같은 기분만 들 뿐...
3. 프로세스 하나가 너무 큰 메모리를 가질 경우
얼마나 큰 것이 큰지는 모르겠지만, 전체 어레이는 수 GB이고, 프로세스 하나당은 보통 ~100MB 이내의 데이터를 다룹니다. 그래서 대단히 큰 메모리는 아닐거라고 생각되네요. 어쨌든 일러주신대로 버벅일때 한번 Ctrl+c 해보았는데, 죽은 프로세스를 다시 살리는 중은 아닌 것으로 보여요. (self._recv() 같은데서 안 걸리고, pool.join()에서 걸렸습니다.) 필요한 계산보다는 어딘가 오버헤드에서 시간을 많이 보낸다는 의심은 좀 더 커지긴 하네요.
바뀐 상황
어디선가 mp.Pool 보다 mp.process를 바로 돌리는게 더 빠르다는 이야길 들어서
process로 돌아가도록 코드를 수정했습니다. 더 빨리 도는것 같은 기분만 듭니다.
새로운? 관측 결과
스크립트를 두 개 이상 돌릴때 확실히 많이 느려집니다.
스크립트당 사용되는 코어 숫자를 다 합쳐도 전체 코어의 절반도 안 되지만 그런 일이 발생하네요.
심지어는 2코어짜리 스크립트와 4코어짜리 스크립트를 같이 돌려도 엄청 느려져요. 전체는 48코어입니다.
얼마나 차이가 나냐 하면..
여기서 6,8번 라인의 결과 (4, 2코어)는 동시에 두 개의 (문제의 그) 스크립트가 돌아가던 상황이었습니다. 각각 3코어, 8코어 였던 것 같아요.
마침 그 다음에 8코어짜리 계산이 끝났고, 속도가 정상이 되었습니다.
20코어 40코어가 별 차이 없는건 오버헤드라고 생각이 되고, 마지막에 4코어 한번 더 돌린건 104ms로 처음의 828ms 보다 8배 가량 빨라졌네요.
다른 스크립트가 하나 끝난 차이로..
참고로 4코어 제온(1230v3였나..?) 컴퓨터에서 위의 테스트를 했을때는 4코어 2코어에서 각각 103, 115ms가 나왔습니다. 그러니 위에서 마지막 4코어 104ms는 정상적인 속도로 보이네요. (하지만 이 순간에도 남은 3코어짜리 스크립트는 엄청 느리게 돌았습니다.)
문제의 스크립트를 4코어 제온 컴퓨터에서 돌려보았습니다.
2코어로 큰 루프 하나 돌리는데 83초, 3코어로 56초가 걸리더군요. 심지어 데이터 로딩도 티가나게 빠르네요. (840pro의 힘일까요?, 서버는 dell의 SAS 외장스토리지인데 여기는 7200rpm 하드 여섯개씩 RAID6로 묶여있어서 파일이 잘 모아져있다는 가정하에는 특별히 느릴 것 같지 않아요. 사실 메모리에 통째로 캐싱 되어있어야 정상인 상황이기도 합니다. - 그런데도 불구하고 데스크탑에서 새로 읽는것 보다 캐싱되었어야할 메모리에서 불러오는게 더 느려보이네요..? 가만보니 너무 이상하네?? )
같은 계산을 서버에서 하면 8코어 기준으로 운이 좋아서 빠를때는 5분 정도, 느릴때는 20분 가까이 걸립니다. 아주 그냥 지 맘대로..
4코어로 해도 대중없이 속도가 오르락 내리락해서 역시 5분 ~ 20분 사이입니다.
글을 쓰다보니 이제는 서버 자체에 의심이 좀 생기네요.
이전에도 한번 간단한 cython 코드를 싱글코어로 돌리는데 노트북보다 훨씬 느려서 이상했던 기억이 있어요. 몇 달 전이라 잘 기억은 안 나지만..
그 당시에 서버에 문제가 있나 싶어서 phoronix test suit을 다운받아서 몇가지 벤치마킹을 돌려보았는데, 제대로 알고 돌린건 아니지만 그 당시 판단으로 "문제 없군" 결론을 내렸던 기억이 납니다.
하지만 자꾸..
메모리 대역폭 자체에 문제가 있거나, 4개의 CPU끼리 링크에 문제가 있거나, 여튼 뭔가 서버 자체에 문제가 있는건 아닐까 하는 의심이 생깁니다.
근데 뭘 어떻게 측정해야할지 모르겠네요. 당장 서버실에 갈 수도 없고요..
쓰로틀링이 걸리나 싶어서 cpu 온도 확인해봤고 클럭도 확인해봤는데 문제없이 잘 돌더라고요. 메모리가 고장났나..?!
테스트를 위해 간단한 코드를 하나 짜봤습니다.
단순한 계산이라 오버헤드가 더 크겠지만 머신별 비교를 위해서..
(본문에 코드 집어넣으려면 어떻게 하나요?)
위의 코드를 제온 데스크탑에서 돌렷을때와 서버에서 돌렸을때 결과입니다.
| 서버 (Ubuntu 15.04, Linux 3.19) | 데스크탑 (Ubuntu 14.04.3, Linux3.13) |
2코어 | 123초 | 24초 |
4코어 | 140초 | 31초 |
8코어 | 197초!! | 없음 |
서버에는 아주 기본적인 (제가 알지 못하는..) 것들 말고는 아무것도 안 돌아가는 상황입니다.
이정도면 서버에서 프로세스를 만드는 자체에 문제가 있는걸까요?
왜 뭐가 문제일까요. 으헝헝