2014-11-30 24 views
7

Tôi đóng góp cho một ứng dụng mã nguồn mở C++. Trong ứng dụng đó là tất cả khai thác gỗ thực hiện với dòng nhưhiệu suất ghi nhật ký và toán tử <<

if (Debug) std::cout << "MyClass | my debug message" << MyExpensiveStringConvertion() << std::endl; 

được sử dụng để sử dụng khung đăng nhập tiên tiến hơn (trong các ngôn ngữ khác) Tôi đề nghị sử dụng một trong các khuôn khổ hiện có như tăng cường, easylogginppp, bất cứ điều gì mà không Formating tự động và có thể được cấu hình trong thời gian chạy.

nhưng tôi đã trả lời rằng việc sử dụng "if (Debug)" hầu như không có chi phí trong khi writting

Log(debug) << "MyClass | my debug message" << MyExpensiveStringConvertion() 

đòi hỏi cả hai tính toán của < < điều hành và MyExpensiveStringConvertion() sự kiện khi đăng nhập bị vô hiệu hóa. Đối số này có chính xác không? nếu nó là chính xác, chúng ta nên quan tâm? Có vẻ như hầu hết các khung công tác đăng nhập đều hoạt động theo cách đó nên rõ ràng hầu hết các nhà phát triển không quan tâm đến việc cập nhật

: "#define LOG (cấp độ) nếu (doDebug (level)) Log (cấp độ)" mà Dietmar Kühl đề cập đến.

+3

Điều đó là đúng, với thực tế là 'MyExpensiveStringConver [s] ion()' được gọi là im nhiều hơn portant hơn là đánh giá '<<'. – Ryan

+1

Hầu hết các khung khai thác gỗ đều là rác rưởi. Đó là lý do tại sao tôi đã viết của riêng tôi. – doc

+0

@doc Tôi cũng vậy, mặc dù tôi gặp phải vấn đề khó chịu trong sản xuất nhưng có lẽ một khung thích hợp sẽ bị xử lý (ví dụ: nhật ký không thành công vì ai đó đã nhân bản quá trình này và để lại một tay cầm mồ côi trên tệp nhật ký của tôi) –

Trả lời

0

Nhờ tất cả các áp phích Tôi biết có thể trả lời câu hỏi của riêng tôi.

Các if (Debug) trông hiệu quả hơn nhưng hầu hết khung đăng nhập dường như được thực hiện theo cách như vậy mà họ trên thực tế bao gồm các trick mentionnned bởi áp phích khác

Ví dụ easylogging ++ có DLOG và DCLOG được cả hai thực hiện như #define DCLOG (CẤP, ...) if (_ELPP_DEBUG_LOG) làm tắc nghẽn (CẤP, VA_ARGS)

và Glog (google khai thác gỗ) cũng có một DLOG mà cũng hoặc là kiểm tra một biến toàn cầu hoặc có thể được vô hiệu hóa tại thời gian biên dịch. tài liệu Glog cũng cho biết "" " Macro ghi điều kiện được cung cấp bởi glog (ví dụ: CHECK, LOG_IF, VLOG, ...) được triển khai cẩn thận và không thực thi biểu thức bên tay phải khi điều kiện là sai. , kiểm tra sau đây có thể không hy sinh hiệu suất của ứng dụng của bạn

kIỂM TRA (obj.ok) < < obj.CreatePrettyFormattedStringButVerySlow();. """

tôi đoán tăng khai thác gỗ cũng thực hiện thủ đoạn hiệu suất tương tự

4

Vấn đề chính không có điều kiện trước thao tác đầu ra là tất cả đối số đang được đánh giá. Nó rất dễ dàng để ngắn mạch các hoạt động đầu ra thực tế (chỉ cần đảm bảo rằng Log(debug) trả về một luồng với std::ios_base::failbit đặt ở trạng thái của nó) nhưng đánh giá tất cả các đối số có xu hướng liên quan đến phí mà bạn không muốn chi tiêu trong quá trình ghi nhật ký. Tất nhiên, bạn có thể sửa chữa các ký hiệu cho khai thác gỗ sử dụng một cái gì đó giống như

#define LOG(level) if (doDebug(level)) Log(level) 

... và sau đó sử dụng

LOG(debug) << "MyClass | my debug message" << MyExpensiveStringConversion(); 
+0

ý tưởng, nhưng tôi đã được dự kiến ​​rằng loại thủ thuật hiệu suất để đi ra khỏi hộp trong hầu hết các khuôn khổ logger, phải không? –

1

Nếu bạn mong đợi ứng dụng của bạn sử dụng một lượng khổng lồ khai thác gỗ sau đó tùy chọn đầu tiên sẽ tạo sự khác biệt lớn.
Nếu không, nó không thực sự quan trọng.

Bạn có thể bọc chức năng nhật ký trong macro để dễ dàng vô hiệu hóa khi biên dịch thành thời gian cho mục đích chuẩn.

#ifdef LOG_ENABLED 
    #define LOGSTR(x) do { \ 
        debug && Log(debug) << x << MyExpensiveStringConvertion() \ 
     } while (0) 
#else 
    #define LOGSTR(x) (void)0 
#endif 
+1

Tốt hơn là nên xác định '#define LOGSTR (x) (void) 0' trong nhánh' # else'. Nếu không mã như thế này 'nếu (một cái gì đó) LOGSTR (" blahblah ");' có thể không thể đoán trước (sẽ cung cấp cho bạn biên dịch lỗi trong hầu hết các trường hợp). +1 anyway. – doc

+0

@doc 'do {} trong khi (0)' là cách mạnh mẽ nhất, [xem tại đây] (http://stackoverflow.com/questions/154136/do-while-and-if-else-statements-in-cc -macros) –

+0

Cố định theo nhận xét hữu ích. – egur

1

Điều đó là chính xác. Một thử nghiệm đơn giản đối với một giá trị boolean (if (Debug)) là giá rẻ và sẽ bỏ qua chuỗi đắt tiền 'Convertion' theo yêu cầu của tuyên bố không đủ tiêu chuẩn Log(debug). Mã này thực chất số tiền:

test some_register, Debug 
jne skip_the_debug_crap 
-- potentially lots of code here -- 

skip_the_debug_crap: 
carry on... 

Versus:

call ExpensiveStringConversion 
call operator << with result (maybe, depends on what class is returned by conversion) 
call operator << for whatever class Log(debug) evaluates to (with test for debug in callee) 
clean up after function call 
carry on... 

(trên thực tế, điều này là hơi đơn giản và không hoàn toàn chính xác như các cuộc gọi đến operator<< được LR kết) Bạn đang tìm kiếm tại nhiều cuộc gọi mỗi thời gian, một số đắt tiền, cho dù kết quả có cần phải được đăng nhập hay không. Ngoài ra, nếu Log(debug)ExpensiveStringConversion không phải là noexcept, sẽ có thêm một số chi phí bổ sung cần thiết để thư giãn tiềm ẩn.

Các giải pháp được đề xuất sử dụng macro biên dịch có nghĩa là không có thay đổi khởi động hoặc thời gian chạy nào có thể để ghi nhật ký cấu hình.

On chỉnh sửa: các pseudo-lắp ráp giống như chưng cất (kiểm tra, jne, cuộc gọi) không có nghĩa là để đại diện cho một kiến ​​trúc x86

Các vấn đề liên quan