좋아, 당신은 개선의 여지가별로없는 것처럼 문제를 정의하고 있습니다. 내 경험상 그것은 매우 드 rare니다. 나는 1993 년 11 월 Dr. Dobbs 기사에서 명백한 낭비가없는 기존의 잘 설계된 비 사소한 프로그램에서 시작하여 벽시계 시간이 48 초에서 단축 될 때까지 일련의 최적화를 통해 설명했습니다. 1.1 초로, 소스 코드 크기는 4 배 줄었습니다. 내 진단 도구 는 다음과 같습니다 . 변경 순서는 다음과 같습니다.
발견 된 첫 번째 문제점은 목록 클러스터 (현재 "반복자"및 "컨테이너 클래스")를 절반 이상 사용하는 것입니다. 그것들은 상당히 간단한 코드로 대체되어 시간이 20 초로 단축되었습니다.
이제 가장 큰 타임 테이커는 더 많은 목록 작성입니다. 백분율로 보면 이전에는 그리 크지 않았지만 이제는 더 큰 문제가 제거 되었기 때문입니다. 속도를 높이는 방법을 찾으면 시간이 17 초로 줄어 듭니다.
이제 명백한 범인을 찾기가 더 어렵지만, 내가 할 수있는 몇 가지 작은 것들이 있으며 시간은 13 초로 떨어집니다.
이제 벽에 부딪힌 것 같습니다. 샘플은 정확히 무엇을하고 있는지 알려주지 만 개선 할 수있는 것을 찾을 수없는 것 같습니다. 그런 다음 프로그램의 기본 디자인, 트랜잭션 중심 구조에 대해 생각하고 수행중인 모든 목록 검색이 실제로 문제의 요구 사항에 의해 지시되는지 묻습니다.
그런 다음 프로그램 코드가 더 작은 소스 세트에서 실제로 (전 처리기 매크로를 통해) 생성되고 프로그램이 프로그래머가 알고있는 것을 지속적으로 파악하지 못하는 재 설계에 착수했습니다. 다시 말해, 일련의 작업을 "해석"하지 말고 "컴파일"하십시오.
- 재 설계가 완료되고 소스 코드가 4 배 줄어들고 시간이 10 초로 줄어 듭니다.
이제는 점점 빨라지기 때문에 샘플링하기가 어렵 기 때문에 10 배나 많은 작업을 수행하지만 다음 시간은 원래 작업량을 기준으로합니다.
더 많은 진단은 대기열 관리에 시간을 보내고 있음을 나타냅니다. 인라인으로 시간을 7 초로 줄입니다.
이제 큰 시간을 보냈다는 것은 내가하고 있던 진단 인쇄입니다. 플러시-4 초.
이제 가장 큰 타임 테이커는 malloc을 호출 하고 무료 입니다. 개체 재활용-2.6 초
계속해서 샘플을 보더라도 여전히 1.1 초라는 꼭 필요한 작업은 없습니다.
총 속도 향상 요소 : 43.6
이제 두 프로그램이 비슷하지는 않지만 장난감이 아닌 소프트웨어에서는 항상 이와 같은 진행 상황을 보았습니다. 먼저 수익이 줄어들 기 전까지는 쉬운 일을하고 더 어려운 일을합니다. 그렇다면 당신이 얻는 통찰력은 다시 디자인이 줄어들어 다시 줄어드는 수익에 도달 할 때까지 새로운 속도 향상을 시작합니다. 이제이이 있는지 궁금해에 적합 할 수 있습니다되는 지점입니다 ++i
또는 i++
또는 for(;;)
또는 while(1)
입니다 빨리 : 나는 스택 오버플로에 너무 자주 볼 질문의 종류.
PS 왜 프로파일 러를 사용하지 않았는지 궁금 할 것입니다. 이에 대한 답은 이러한 "문제"중 거의 모든 것이 샘플을 정확하게 찾아주는 함수 호출 사이트라는 것입니다. 오늘날에도 프로파일 러는 전체 함수보다 명령문 및 호출 명령이 위치를 찾고 수정하기가 더 중요하다는 생각을 거의 듣지 않고 있습니다.
실제로이 작업을 수행하기 위해 프로파일 러를 구축했지만 코드가 수행하는 작업에 대한 불길하고 친밀한 친밀감을 얻으려면 손가락을 바로 넣을 수 없습니다. 발견되는 문제가 너무 작아서 쉽게 놓칠 수 없기 때문에 샘플 수가 적다는 것은 문제가되지 않습니다.
추가 : jerryjvl이 몇 가지 예를 요청했습니다. 첫 번째 문제는 다음과 같습니다. 시간이 절반 이상 걸리는 소수의 개별 코드 줄로 구성됩니다.
/* IF ALL TASKS DONE, SEND ITC_ACKOP, AND DELETE OP */
if (ptop->current_task >= ILST_LENGTH(ptop->tasklist){
. . .
/* FOR EACH OPERATION REQUEST */
for ( ptop = ILST_FIRST(oplist); ptop != NULL; ptop = ILST_NEXT(oplist, ptop)){
. . .
/* GET CURRENT TASK */
ptask = ILST_NTH(ptop->tasklist, ptop->current_task)
이들은 목록 클러스터 ILST (목록 클래스와 유사)를 사용하고있었습니다. 그것들은 일반적인 방법으로 구현되며, "정보 숨기기"는 클래스 사용자가 구현 방식에 신경 쓸 필요가 없다는 것을 의미합니다. 이 줄이 작성되었을 때 (약 800 줄의 코드 중), 이것이 "병목 현상"(나는 그 단어를 싫어한다) 일 수 있다는 생각에 대해서는 생각하지 않았다. 그들은 단순히 일을하는 권장 방법입니다. 가급적이면 이러한 것들을 피해야한다고 말하기는 쉽지만 내 경험상 모든 성능 문제는 이와 같습니다. 일반적으로 성능 문제가 발생하지 않도록하는 것이 좋습니다. "피해야 했음"(후시)에도 생성 된 것을 찾고 수정하는 것이 더 좋습니다.
두 번째 문제는 두 줄로 나뉘어져 있습니다.
/* ADD TASK TO TASK LIST */
ILST_APPEND(ptop->tasklist, ptask)
. . .
/* ADD TRANSACTION TO TRANSACTION QUEUE */
ILST_APPEND(trnque, ptrn)
이들은 끝에 항목을 추가하여 건물 목록입니다. (수정은 항목을 배열로 수집하고 한 번에 목록을 작성하는 것이 었습니다.) 흥미로운 점은 이러한 문장이 원래 시간의 3/48에 불과하기 때문에 비용이 들지 않았다는 것입니다. 사실 처음 에는 큰 문제 입니다. 그러나 첫 번째 문제를 제거한 후 3/20의 시간이 소요되어 이제는 "더 큰 물고기"가되었습니다. 일반적으로 그렇게됩니다.
이 프로젝트가 내가 도와 준 실제 프로젝트에서 증류되었다고 덧붙일 수 있습니다. 이 프로젝트에서 내부 루프 내에서 데이터베이스 액세스 루틴을 호출하여 작업이 완료되었는지 확인하는 등 성능 문제가 훨씬 더 급격했습니다.
참고 ADDED : 소스 코드, 모두 원본과 재 설계는에서 찾을 수 있습니다 www.ddj.com 파일 9311.zip 파일 slug.asc 및 slug.zip에서, 1993.
2011/11/26 편집 : 이제 Visual C ++에 소스 코드가 포함 된 SourceForge 프로젝트 와 조정 방법에 대한 자세한 설명이 있습니다. 그것은 위에서 설명한 시나리오의 전반부를 통과하며 정확히 동일한 순서를 따르지 않지만 여전히 2-3 배의 속도 향상을 얻습니다.