2006년에 SI회사에 있을때 썻던글을 수정없이 올렸습니다. 참고하세요.
퍼포먼스의 최고의 화두는 누가 머라고 해도 DISK IO다. 컴퓨팅시스템에서 상대적으로 가장느린놈이 이놈이다. SSD와 같은 메모리 디스크가 있지 않느냐라고 얘기하는 사람이 있다면 지금당장 뒤로가기 버튼을 누루는것이 정신건장에 유익하겠다.
다스크에 즉 영구저장장치의 제1의 요구사항은 영구성이다. 전원이 끊어져도 저장한데이타는 유지되어야 한다. 그래서 항상 운영체계(KERNEL) 또는 시스템 개발자는 디스크에 정확히 쓰여졌는지 확인해야한다 또한 디스크 같이 대용량 데이타를 필요에 따라 쉽고 빠르게 잡근하기위에 파일이나 디렉토리와 같은 개념(INODE)으로 인덱싱하는데 이 인덱스와 데이타가 불일치하게되면 디스크의 기본기능을 못하는 쓰레기가 된다. 그래서 물리적인 속도뿐만 아니라 무결성 측면에서도 많은 코스트를 감수할수밖에는 없는것이다.
아이폰과 갤럭시를 비교해보자 하드웨어사양은 아이폰이 딸리는데도 불구하고 아이폰이 더 빠르다고 느껴지지 않는가? 여러가지 이유가 있겠지만 가장 근원적인 이유는 배터리 탈착이다. 디스크 얘기하다가 왠 배터리? 위에서 얘기했지만 디스크는 어떤한 상황이 와도 데이타가 보존 되어야한다. 그런데 포터블 기기라는 특수한 상황이기 때문에 사용자가 데이타 저장시 디스크에 저장된것이 확인되어야한다. 사용자가 언제 배터리를 빼버릴지 떨어뜨릴지 알수가 없기 때문이다.
그런데 배터리를 단단히 고정하고 사용자가 배터리를 임의데로 뺄수없게 한다면? 모든 즉시성에서 벗어날수있게 되는것이다 시스템이 바쁠때 메모리에 저장해 뒀다가 한가할때 디스크에 쓸수있게 되는것이다. 얼마나 퍼포먼스가 개선되겠냐 하겠지만 아주아주 큰 퍼포먼스 차이를 느낄수있는것이 이방법이다(아주 큰 캐쉬를 사용할수있는것또한 이방법이다)
그럼 원론으로 돌아와서 그래서 어쩌라는것이냐?
결론부터 말하면 디스크 IO를 줄이라는것이다. 위에 얘기한것처럼 디스크는 해당데이타 즉 파일의 위치를 칮는데 많은 코스트를 소요한다. 그러므로 많은데이타를 모아서 한번에 쓰고 읽는 작업을 해야한다는것이다.
예를들어 어떤 스트림으로 부터 부정기적 데이타가 유입된다하면 그때 그때마다 디스크에 저장하는것이 코드상으로 간결하고 편리할것이다. 하지만 최악은 경우 스트림에서 1바이트씩 1기가의 데이타가 들어온다면 시스템은 사망할것이 자명하다.
그럼 몇가지 포인트를 잡아 보겠다.
0. 섹터
: H/W와 성능은 일체다. H/W의 특성을 모르는 상황에서 성능개선은 뜬구름 잡는 얘기다. 섹터는 디스크에 한번에 써넣고 읽는 데이타 단위다. 즉 섹터보다 작은 데이타도 한 섹터만큼의 영역을 가지며 섹터보다 큰 데이타는 여러개의 섹터를 소유한다. 그리고 이 섹타들의 정보를 보관하는것이 I-NODE다. 일반적으로 HDD는 512KB, Flash Memory는 4096KB를 섹터로 가진다.
1. USER LEVEL (사용자 레벨)
: FILE I/O중 USER LEVEL 사용상 편리한 메타데이타와 기능들을 포함한다. 물론 USER LEVEL 함수들은 KERNEL LEVEL 함수들을 호출한다. 간단히 파일입출력이 필요하다면 간단히 아래와 같이 처리할수 있다.
char * data = "test data"; FILE fp = fopen("test.txt", "wt"); fwrite(data, strlen(data), 1, fp); fclose(fp); |
위의 함수들은 USER LEVEL이다. I-NODE Sync라든가 캐쉬처리라든가하는 문제를 Default또는 지정된 방식으로 자체 처리한다. 개발자들은 신경쓸것이 별로 없다. 이말은 돌려서 다시 말하면 성능개선할 부분도 많이 않다는 것을 의미한다. 하지만 여기에도 성능개선 방법은 존재한다.
각각의 버퍼를 만들어서 조각난 데이타 입출력을 섹터크기만큼 모아서 한꺼번에 써넣는것이다. 물론 함정은 존재한다. 버퍼에만 데이타가 존재할때 비정상 종료를 했을때 데이타가 날라갈수 있는 최악의 경우이다. 시스템이 비정상 종료시 파일 데이타 또한 의미가 없거나 비정상종료에 대응할수 있는 H/W 시스템일 갖추어진 시스템에서 사용할수 있겠다.
2. KERNEL LEVEL (시스템 레벨)
: DISK I/O는 언제나 KERNEL을 거친다. 최고의 성능을 내고자한다면 언제나 KERNEL LEVEL의 함수들을 사용하여 최적의 모듈/함수를 구축하는것이 하나의 방법일 것이다.
--> 작성중입니다.
'programming' 카테고리의 다른 글
[Algorithm] C++ 문자열 조합 (combination) (2) | 2023.06.04 |
---|---|
[Algorithm] C++ 미로찾기 (graph traversal ) (0) | 2023.06.03 |
[Algorithm] Graph & Tree (0) | 2023.05.30 |
[Algorithm] Stack 과 Recursive (3) | 2023.05.30 |
퍼포먼스 개선 - 개요(2006년 version) (0) | 2023.03.22 |