Com toi uu ma nguon c c

13 86 0
Com toi uu ma nguon c c

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Com toi uu ma nguon c c tài liệu, giáo án, bài giảng , luận văn, luận án, đồ án, bài tập lớn về tất cả các lĩnh vực kinh...

Tối ưu mã nguôn C/C++ Tại phải tối ưu mã lệnh? Sự đời trình biên dịch đại giúp lập trình viên cải thiện đáng ké thoi gian công sức phát triển phần mềm Một vấn đề đáng quan tâm xu hướng phát triển phần mềm theo hướng trực quan nhanh tiện dụng dần làm mặt kĩ viết mã lệnh lập trình viên giảm rõ rệt họ trơng cậy hoản tồn vào hỗ trợ trình biên dịch Khi phát triển hệ thống phần mềm có tần suất xử lý cao, ví dụ sản phẩm có chức điều phối hoạt động chuyền sản xuất nhà máy, bên cạnh hỗ trợ trình biên dịch mạnh cịn can đến kĩ tối ưu mã lệnh lập trình viên Kĩ tốt biến cơng việc lập trình khơ khan, với đoạn code tưởng chừng lạnh lùng trở nên sinh động Một đoạn mã lệnh tốt tận dụng tối đa ưu điểm ngôn ngữ khả xử lý hệ thống, từ giúp nâng cao đáng kể hiệu suất hoạt động hệ thống Để chương trình hoạt động tối ưu, điều tận dụng hỗ trợ sẵn có trình biên dịch thông qua thị (directive) giúp tối ưu mã lệnh, tốc độ kích thước chương trình Hầu hết trình biên dịch phổ biến hỗ trợ tốt việc tối ưu mã biên dịch Tuy nhiên, để đạt hiệu tốt nhất, lập trình viên cần tập cho thói quen tối ưu mã lệnh từ bắt tay viết chương trình đầu tay Bài viết trình bày số gợi ý co bán kinh nghiệm thực tế tơi ưu lập trình ngơn ngữ C/C++ Tinh giản biểu thức toán học Các làm biêu giản biểu tăng thức biêu thức toán học phức tạp biên dịch sinh nhiều mã dư thừa kích thước chậm tơc độ thực chương trình Do viet phức tạp lập trình viên cân nhớ sơ đặc điêm sau đê giúp tinh thức: - CPU xử lý phép tính cộng trừ nhanh phép tính chia nhân Vi du: + Biểu thức Tofal = (A*B + A*C + A*D) cần phép cộng phép nhân Ta nhóm phép cộng việt thành Total = A*(B+C+D), tơc độ tính nhanh giảm phép tính nhân + Biểu thức Total = (B/A + C/A) cần phép chia viết Total = (B+C)/A, giúp giảm phép chia - CPU xử lý tính tốn với số nguyên (integer) chậm với số thực (float, double), tôc độ xử lý float nhanh double - Trong số trường hợp nhân chia số ngun, sử dụng tốn tử đời bít (bit shifting) sé nhanh hon toan tw nhân chia Vi du: Biểu thức (A *= 128) có thê tận dụng tốn tử dời bit sang trai thành (A MyFunc() ) > max) { // } Ta chuyển hàm MyEunc ngồi biểu thức điều kiệu sau: int if temp value = mydata->MyFunc(); (temp value < min) { // } else if (temp value > max) { // } Đối với biểu thức điều kiện dang switch case: giá trị cho case liên tục nhau, trình biên dịch tạo bảng ánh xạ (còn gọi jump table) giúp việc truy xuất đến điều kiện nhanh giảm kích thước mã lệnh Tuy nhiên giá trị không liên tục, trình biên dịch tạo chuỗi phép tốn so sánh, từ gây chậm việc xử lý: Ví dụ sau cho kết truy xuất tối ưu sử đụng switch case: switch { case (my value) A: break; case B: break; case C: break; case D: default: } Trong trường hợp giá trị dùng cho case khơng liên tục, ta có thé viết thành biêu thức if elseif else nhu sau: switch { case (my value) A: break; case F: break; case T: } Có thể i xử if else i } viết thành: (my value lý if xử == cho A) trường (my value lý cho hợp == trường A F) hop F else { // } trường hợp khác Ø Tơi ưu vịng lặp Vịng lặp thành phần phản ánh khả tính tốn khơng mệt mỏi máy tính Tuy nhiên, việc sử dụng máy móc vịng lặp ngun nhân làm giảm tơc độ thực chương trình Một sơ thủ thuật sau giúp lập trình viên tăng tơc vịng lặp mình: - Đối với vịng lặp có số lần lặp nhỏ, ta viết lại biểu thức tính tốn mà khơng cần dùng vòng lặp Nhờ tiết kiệm khoảng thời gian quản lý tăng biên đêm vịng lặp Ví dụ cho vòng lặp sau: for( int i = 0; i < 4; { array[i] =MyFunc(i); } viết array[0] array[1] = lại thành: MyFunc (0) ; MyFunc(1); it+ ) array[2] = array [3] MyFunc (2); MyFunc (3) ; - Đối với vịng lặp phức tạp có số lần lặp lớn, cần hạn chế việc cấp phát biến nội phép tính lặp lặp lại bên vịng lặp mà khơng liên quan đên biên đếm lặp Ví dụ cho vịng lặp sau: int students number for( int i = 0; i = < 10000; students number; it?+ ) { //nam double MyFune mat nhiéu sample value = CalcStudentFunc(i, thoi gian thuc hién MyFunc(students number); sample value); } Trong ví dụ trên, biển sample_value tính vịng lặp cách khơng cân thiệt hàm MyFunc có thê ton rât nhiêu thời gian, ta có thê dời đoạn mã tính tốn ngồi vịng lặp sau: int students number double for( sample value int i = 0; < = 10000; = MyFunc(students number); students number; i++ ) { CalcStudentFunc(i, sample value); } - Đối với vòng lặp từ đến n phan tir nhu sau: for( int i = 0; i < max number; i†++ ) Nên thực việc lặp từ giá trị max number trở sau: for( int i¡ = max number - 1; i >=0 ; i ) Vì biên dịch thành mã máy, phép so sánh voi (zero) thực nhanh với sô ngun khác Do phép so sánh vịng lặp ( ¡ >=0 ) nhanh phép so sánh (1 < max_number) - Trong vòng lặp lớn, toán tử prefix dạng ( I ++1) thực nhanh hon toản tử postfix (1 1++) Nguyên nhân toán tử prefix tăng giá trị biên trước sau trả kết cho biểu thức, toán tử postfix phải lưu giá trị cũ biến vào biến tạm, tăng giá trị biến trả giá trị biến tạm Tôi ưu việc sử dụng nhớ trỗ Con trỏ (pointer) gọi "niềm tự hào" C/C++, nhiên thực tế nguyên nhân làm đau đầu cho lập trình viên, hầu hết trường hợp sụp đồ hệ thống, hết nhớ, vi phạm vùng nhớ xuất phát từ việc sử dụng trỏ không hợp lý - Hạn chế pointer đereference: pointer đereference thao tác gán địa vùng nhớ liệu cho trỏ Các thao tac dereference tơn nhiêu thời gian có thê gây hậu nghiêm trọng nêu vùng nhớ đích chưa câp phát Ví dụ với đoạn mã sau: for( int i = 0; i < max number; i†++ ) { SchoolData->ClassData->StudentData->Array[i] = my_value; } Bang cach di chuyén cac pointer dereference nhiéu cap ngồi vịng lặp, đoạn mã có thé viét lai nhu sau: unsigned long *Temp Array = SchoolData->ClassData->StudentData- >Array; for( int i = 0; Temp Array[i] = i < max_number; i++ ) { my_value; } - Sử dụng tham chiếu (reference) cho đối tượng liệu phức tạp tham số hàm Việc sử đụng tham chiếu truyền nhận đữ liệu hàm có thê giúp tăng tốc đáng kê cầu trúc liệu phức tạp Trong lập trình hướng đối tượng, đối tượng truyền vào tham số dạng giá trị tồn nội dung đối tượng chép copy constructor thành khác truyền vào hàm Nếu truyền dạng tham chiếu loại trừ việc chép Một điểm cần lưu ý sử dụng tham chiếu giá trị đối tượng có thê thay đổi bên hàm gọi, đo lập trình viên cần sử dụng thêm từ khóa const khơng muốn nội dung đối tượng bị thay đổi Ví dụ: Khi truyền đối tượng dạng giá trị vào hàm dé str dung, copy constructor sé dugc gol void { MyFunc(MyClass A) //copy constructor cla A sé duoc goi int value = A.value; } Khi đùng dạng tham chiếu, đoạn mã có thê viết thành: void MyFunc(const MyClass &A) //không gọi copy constructor { int value = A.value; } - Tránh phân mảnh vùng nhớ: Tương tự việc truy xuất liệu đĩa, hiệu truy xuât liệu vùng nhớ động giảm nhớ bị phần mảnh Một sô gỢI ý sau ø1úp giảm việc phân mảnh nhớ + Tận dụng nhớ tĩnh Ví dụ: tốc độ truy xuất vào mang tinh co tốc độ nhanh truy xuât vào danh sách liên kêt động + Khi cần sử dụng nhớ động, tránh cấp phát giải phóng vùng nhớ kích thước nhỏ Ví dụ ta có thê tận dụng xin câp phát mảng đơi tượng thay đơi tượng riêng lẻ + Sử dụng STL container cho cac đối tượng Các CƠ chế sử dụng nhớ riêng có tối ưu việc cấp phát nhớ STL cung cấp nhiều thuật toán loại liệu giúp tận dụng tối đa hiệu C++ Các bạn tìm đọc sách STL biết thêm nhiều điều thú vị - Sau cấp phát mảng đối tượng, tránh nhằm lẫn sử dụng toán tử delete[] delete: với C++, toán tử delete[] định trình biên dịch xóa chuỗi vùng nhớ, delete xóa vùng nhớ mà trỏ đến, đo gây tượng "rác” phân mảnh nhớ Vị dụ: int *myarray delete = new int[50]; []myarray; Với delete[], trinh bién dich phát sinh mã sau: mov ecx, mov dword mov edx, dword ptr dword push edx call operator add esp,4 ptr [myarray] [ebp-6Ch], ptr ecx [ebp-6Ch] delete[] (495F10h) //goi toán tử delete[ ] Trong với đoạn lệnh: int *myarray delete = new int[50]; myarray; Trinh biên dich sé phat sinh mã sau: mov ecx, mov dword mov edx, dword ptr dword push edx call operator add ptr [myarray] [ebp-6Ch], ptr delete ecx [ebp-6Ch] (495F10h) //goi todn tt: delete esp,4 Sử dụng hợp lý chế lỗi try catch Việc sử dụng không hợp lý bẫy lỗi có thê sai lầm tai hại trình biên địch thêm mã lệnh kiểm tra đoạn mã cài đặt try catch, điều lam tang kích thước giảm tốc độ xử lý chương trình, đồng thời gây khó khăn việc sửa chữa lỗi logic Thống kê cho thấy đoạn mã có sử dụng bẫy lỗi hiệu xuất thực giảm từ 5%-I03% so với đoạn mã thông thường viết cần thận Để hạn chế điều này, lập trình viên nên đặt bẫy lỗi đoạn mã có nguy lỗi cao khả dự báo trước thấp Tận dụng đặc tính xử lý CPU Đề đảm báo tốc độ truy xuất tối ưu, vi xử lý (CPU) 32-bit yêu cầu liệu xếp tính tốn nhớ theo memory alignment Do vay bién dich byte, trình biên dịch bố sung thêm xếp theo quy luật Việc bổ sung liệu, đặc biệt cầu trúc đữ liệu Xem ví dụ sau: class Test { bool a; int c; int d; bool b; offset 4-byte Yêu cầu gọi đối tượng đữ liệu có kích thước 4các byte trồng để đảm bảo đữ liệu làm tăng đáng kế kích thước structure, class Theo nguyên tắc alignment a" "b" chiếm byte biên dịch bô sung byte băng hàm sizeof(Test) sé la 4-byte (hai biến "c" "d" có kích thước byte), biến sau biến biến int chiếm byte, trình cho biên Kêt tính kích thước lớp Test 16 byte Ta có thê xếp lại biến thành viên lớp Test sau theo chiều giảm dần kích thước: class Test { int c; int d; bool a; bool b; }z Khi đó, hai bién "a" va "b" chiém byte, trình biên dịch cần bố sung thêm byte sau biến "b" để đảm bảo tính xếp 4-byte Kết tính kích thước sau xếp lại class Test 12 byte Tận dụng số ưu điểm khác C++ - Khi thiết kế lớp (class) hướng đối tượng, ta có thê sử dụng phương thức "inline" để thực xử ly đơn giản cần tốc độ nhanh Theo thống kê, phương thức inline thực nhanh khoảng 5-10 lần so với phương thức cài đặt thông thường - Sử dụng ngôn ngữ cấp thấp assembly: ưu điểm ngôn ngữ C/C++ khả cho phép lập trình viên chèn mã lệnh hợp ngữ vào mã nguồn C/C++ thông qua từ khóa asm { } Lợi giúp tăng tốc đáng kế biên dịch chạy chương trình Vi du: int a, e a*b = b, c, + d, e; a*c; Trình biên dịch phát sinh mã hợp ngữ sau: mov imul mov imul eax, eax, ecx, ecx, dword dword dword dword ptr ptr ptr ptr [a] [b] [a] [c] add eax, ecx mov dword ptr [e], eax Tuy nhiên, ta viết rút gọn giảm phép imul (nhân), phép mov (di chuyên, chép): asm { mov eax, b; add eax, Cc; imul mov eax, e, a; eax; }z - Ngôn ngữ C++ cho phép sử dụng từ khóa 'register" khai báo biến để lưu trữ liệu biên ghi, giúp tăng tôc độ tính tốn truy xt liệu ghi nhanh truy xuât nhớ Vi du: for (register int i; i

Ngày đăng: 18/01/2018, 13:05