2013-08-16 25 views
5

Tôi chỉ làm việc thông qua tài liệu của http://www.gnu.org/software/gettext/manual/gettext.html và không có thảo luận nào về chi phí hoạt động. Trên internet, tôi chỉ tìm thấy các cuộc thảo luận hiệu suất cho các ngôn ngữ khác (PHP và Java) nhưng không có gì cho C/C++.chi phí thực hiện của hệ thống quốc tế hóa gettext trong C/C++

Vì vậy câu hỏi của tôi:?

  1. trên không thực hiện trong quá trình khởi động của một chương trình sử dụng gettext (thư viện chia sẻ tải như thế nào các bản dịch được nạp vào bộ nhớ là gì Có phải tất cả các bản dịch nạp khi khởi động hoặc on- nhu cầu?)

  2. Hình phạt hiệu suất trong hoạt động bình thường của chương trình là gì? (ví dụ: khi cần dịch thuật) Mức độ tăng bộ nhớ của chương trình là bao nhiêu và bộ nhớ được tổ chức như thế nào? Có nguy cơ/khả năng cao hơn mà các phần của chương trình được hoán đổi vào đĩa khi chương trình không hoạt động? (Nếu các bản dịch được lưu trữ trong một phần rất khác của bộ nhớ so với phần còn lại của chương trình, thì theo hiểu biết của tôi về khả năng xảy ra lỗi trang cao hơn so với phiên bản chưa được quốc tế hóa của chương trình)

  3. Có một chương trình chạy theo "C" -locale cũng bị các hình phạt hiệu suất?

Cảm ơn rất nhiều.

+0

Một chương trình sử dụng 'gettext' đang tạo ra kết quả có thể đọc được của con người. Các chi phí thấp hơn là nó sẽ đưa con người đọc văn bản, vì vậy có thể được coi là không đáng kể. (Điều đó không hoàn toàn đúng, nhưng thực tế, chi phí là _not_ một vấn đề.) –

+0

@JamesKanze chương trình cũng có thể tạo ra các báo cáo dài, hoặc nó có thể gửi email hàng loạt cá nhân, hoặc ... Đó là đầu ra là con người có thể đọc được ngụ ý rằng có một con người xung quanh, và chương trình có thể dừng lại cho đến khi anh/cô ấy đọc xong kết quả. – Chris

+0

@James: Ngay cả một byte bị thiếu duy nhất gây ra lỗi trang sẽ gây ra sự chậm trễ đáng chú ý ngay cả bởi con người. Trong trường hợp cực đoan, nó có thể gây ra sự chậm trễ vài giây nếu đĩa cứng phải được tách ra. Ngoài ra khá nhiều chương trình dòng lệnh được bắt đầu từ các tập lệnh có thể có nghĩa là một chương trình được khởi động/dừng lại hàng nghìn lần. Nhưng điểm thực sự là "nó negleglible" không phải là một câu trả lời cho các câu hỏi vì nó chỉ negleglible trong một số trường hợp. – Robby75

Trả lời

3

Cho rằng các thay thế cho phương pháp này là phải có một số lượng lớn các bản xây dựng, đều có một cái gì đó như thế này trong nó:

int main() 
{ 
    printf(
#ifdef SWEDISH 
      "Hej världen\n" 
#elsif ENGLISH 
      "Hello, World\n" 
#elsif PORTUGUESE 
      "Olá, Mundo\n" 
#else 
    #error Language not specified. 
#endif 
    ); 
    return 0l; 
} 

thay vì chúng tôi nhận được:

int main() 
{ 
    printf(gettext("Hello, World\n")); 
} 

đó là dễ dàng để đọc và hiểu.

Tôi không biết cấu trúc chính xác của triển khai gettext, nhưng tôi cho rằng đó là bảng băm khi nó được tải. Có thể là cây nhị phân, nhưng bảng băm có vẻ hợp lý hơn.

Đối với chi phí chính xác, rất khó để đặt một số trên đó - đặc biệt, như bạn nói, nếu có thứ gì đó được đổi vào đĩa và đĩa đã dừng, phải mất 3-4 giây để lấy đĩa đến tốc độ. Vậy làm thế nào để bạn định lượng? Có, có thể trang cần thiết cho gettext được hoán đổi nếu hệ thống đang bận làm việc gì đó bộ nhớ chuyên sâu.

Tải tệp tin tin nhắn chỉ nên là phí lớn nếu tệp quá lớn, nhưng một lần nữa, nếu đĩa không quay, và tệp không được lưu trong bộ nhớ cache thì sẽ có một vài giây. Một lần nữa, làm thế nào để định lượng đó. Kích thước của tệp rõ ràng tỷ lệ thuận với kích thước thực tế của các bản dịch (hoặc ngôn ngữ bản địa).

Về điểm 2:

Theo như tôi biết, trong cả Linux và Windows, các trang được đổi chỗ ra vào một "thời gian gần đây nhất là sử dụng" (hoặc một số sử dụng thống kê khác) cơ sở, trong đó có liên quan gì đến nơi họ đang ở. Rõ ràng các thông điệp đã dịch ở một nơi khác với mã thực tế - không có danh sách 15 bản dịch khác nhau trong tệp nguồn, do đó các bản dịch được tải trong thời gian chạy và sẽ được đặt ở một vị trí khác với chính mã.Tuy nhiên, chi phí của việc này là tương tự như sự khác biệt giữa chi phí:

static const char *msg = "Hello, World\n"; 

static const char *msg = strdup("Hello, World\n"); 

Cho rằng văn bản chuỗi thường được lưu giữ cùng trong nhị phân của một chương trình dù sao, tôi không nghĩ rằng "sự gần gũi" của chúng đối với mã thực thi có sự khác biệt đáng kể so với một mảng bộ nhớ được phân bổ động ở đâu đó trong heap. Nếu bạn gọi hàm gettext thường đủ, bộ nhớ đó sẽ được giữ "hiện tại" và không được hoán đổi. Nếu bạn không gọi gettext trong một thời gian, nó có thể bị hoán đổi. Nhưng điều đó áp dụng cho "không có chuỗi nào được lưu trữ trong tệp thi hành đã được sử dụng gần đây, vì vậy chúng đã được hoán đổi".

3) Tôi nghĩ tiếng Anh (hoặc "không chọn ngôn ngữ") được xử lý chính xác giống với bất kỳ biến thể ngôn ngữ nào khác.

tôi sẽ có một chút đào hơn nữa trong một chút, cần ăn sáng đầu tiên ...

Rất không khoa học:

#include <libintl.h> 
#include <cstdio> 
#include <cstring> 

static __inline__ unsigned long long rdtsc(void) 
{ 
    unsigned hi, lo; 
    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 
    return ((unsigned long long)lo)|(((unsigned long long)hi)<<32); 
} 


int main() 
{ 
    char str[10000] = {}; 
    char *s = str; 
    unsigned long long time; 

    for(int i = 0; i < 10; i++) 
    { 
    time = rdtsc(); 
    s += sprintf(s, "Hello, World %d", i); 
    time = rdtsc() - time; 
    printf("Time =%lld\n", time); 
    } 
    printf("s = %s\n", str); 
    s = str; 

    strcpy(s, ""); 
    for(int i = 0; i < 10; i++) 
    { 
    time = rdtsc(); 
    s += sprintf(s, gettext("Hello, World %d"), i); 
    time = rdtsc() - time; 
    printf("Time =%lld\n", time); 
    } 
    printf("s = %s\n", str); 
} 

Cung cấp cho kết quả như sau:

$ g++ -Wall -O2 intl.cpp 
$ ./a.out 
Time =138647 
Time =9528 
Time =6710 
Time =5537 
Time =5785 
Time =5427 
Time =5406 
Time =5453 
Time =5644 
Time =5431 
s = Hello, World 0Hello, World 1Hello, World 2Hello, World 3Hello, World 4Hello, World 5Hello, World 6Hello, World 7Hello, World 8Hello, World 9 
Time =85965 
Time =11929 
Time =1
Time =10226 
Time =10628 
Time =9613 
Time =9515 
Time =9336 
Time =9440 
Time =9095 
s = Hello, World 0Hello, World 1Hello, World 2Hello, World 3Hello, World 4Hello, World 5Hello, World 6Hello, World 7Hello, World 8Hello, World 9 

Các mã trong dcigettext.c sử dụng hỗn hợp tìm kiếm nhị phân trong một mảng phẳng của chuỗi và hàm băm có chứa chuỗi để băm PJW (xem: http://www.cs.hmc.edu/~geoff/classes/hmc.cs070.200101/homework10/hashfuncs.html).

Vì vậy, chi phí, khi ứng dụng đã bắt đầu, có vẻ như là "chỉ đáng chú ý" (khi đếm đồng hồ), nhưng không lớn.

Thời gian chính xác để chạy sprintf đầu tiên có phần khác nhau trong cả hai trường hợp, vì vậy tôi sẽ không nói rằng "sử dụng gettext" làm cho sprintf nhanh hơn trong lần gọi đầu tiên - chỉ "may mắn" trong lần chạy này (I đã có một vài biến thể khác của mã và tất cả chúng thay đổi rất nhiều vào lần gọi đầu tiên đến sprintf và ít hơn cho các cuộc gọi sau này). Có lẽ một số thiết lập (có thể cache [printf gây ra cache được ghi đè với rác khác là khá có thể], dự đoán chi nhánh, vv) một nơi nào đó mà mất thêm thời gian ...

Bây giờ, điều này rõ ràng không trả lời câu hỏi của bạn về phân trang ra ngoài, vv Và tôi đã không cố gắng tạo một bản dịch tiếng Thụy Điển, tiếng Bồ Đào Nha hoặc tiếng Đức của thông điệp "Hello, World" của tôi. Tôi vẫn tin rằng nó không lớn, trừ khi bạn thực sự chạy 100 giây instantiations của một ứng dụng trong một giây, và ứng dụng đó không làm được gì khác ngoài việc in một tin nhắn tới màn hình sau khi thực hiện một số phép tính đơn giản, chắc chắn, nó có thể quan trọng .

Cách duy nhất REAL để tìm ra mức độ chênh lệch mà nó tạo ra là áp dụng cùng một ứng dụng với #define _(x) x thay vì #define _(x) gettext(x) và xem bạn có nhận thấy bất kỳ sự khác biệt nào không.

Tôi vẫn nghĩ rằng "phân trang" là một cá trích đỏ. Nếu máy ở dưới áp suất bộ nhớ CAO thì nó sẽ chạy chậm bất kể cái gì (Nếu tôi viết một đoạn mã phân bổ 16GB [Tôi có RAM 16 GB trong máy] trên máy của mình, mọi thứ ngoại trừ chính bàn phím (có thể nhấp nháy đèn num-lock) và con trỏ chuột (có thể di chuyển con trỏ chuột trên màn hình) không phản hồi).

+0

Cảm ơn bạn đã trả lời; Một bảng băm có nghĩa là AFAIK cho mỗi bản dịch, một băm sẽ phải được tạo ra khi chạy và băm phải được tìm thấy trong bảng. Trong trường hợp đó, ứng dụng "Hello World" của bạn có thể chạy chậm hơn vài lần so với không có gettext. – Robby75

+0

về điểm 2: Nó rất quan trọng nơi chúng được đặt. Khi chúng được đặt gần chương trình chính, cơ hội là rất cao mà cả hai đều trên cùng một trang! Một chương trình được trải ra trên nhiều trang sẽ khiến nhiều trang bị thiếu hơn một chương trình chỉ sử dụng một trang. – Robby75

+0

Có, nhưng để văn bản nằm trên cùng một trang với mã của bạn yêu cầu mã rất nhỏ (nhỏ hơn 4KB). Nếu chúng ta đang nói về một số mã thực sự làm một cái gì đó có ý nghĩa và hữu ích, ngoài việc in "Hello, World \ n", thì có khả năng là mã và văn bản của nó bao gồm nhiều hơn một trang ở ít nhất. Tính toán băm cho một chuỗi không hoàn toàn nhỏ, nhưng đơn giản hơn việc xử lý printf thực hiện cho chuỗi định dạng, vì vậy tôi không tin rằng bạn đang ở đó. Nhưng tôi đã ăn sáng, bây giờ nhìn vào những gì libintl thực sự làm. –

1

Một số phép đo:

for (; n > 0; n--) { 
#ifdef I18N 
      fputs(gettext("Greetings!"), stdout); 
#else 
      fputs("Greetings!", stdout); 
#endif 
      putc('\n', stdout); 
    } 

Với n = 10000000 (10 triệu), và đầu ra chuyển hướng đến một tập tin. Không có tệp po cho ngôn ngữ, vì vậy chuỗi gốc được in (tệp đầu ra giống hệt nhau). thời gian sử dụng trong vài giây:

  • 0,23 với I18N không xác định
  • 4,43 với I18N
  • 2.33 với I18N và LC_ALL = C

Overhead 0,4 micro giây cho mỗi cuộc gọi. (Trên Phenom X6 @ 3.6GHz, Fedora 19). Với LC_ALL = C, chi phí chỉ là 0,2 µs. Lưu ý rằng đây có lẽ là trường hợp xấu nhất - thường bạn sẽ làm điều gì đó khác trong chương trình của bạn. Tuy nhiên, nó là một yếu tố của 20, và bao gồm IO. gettext() là khá chậm hơn tôi đã mong đợi.

Sử dụng bộ nhớ Tôi chưa đo, vì nó có thể phụ thuộc vào kích thước của tệp po. Thời gian khởi động tôi không có ý tưởng làm thế nào để đo lường.

+0

Có thể đặt n thành 1 và khởi động nó trong một tập lệnh: 'for i in \' seq 10000000 \ '; do run_test_program; done' để đo thời gian khởi động. Trong thực tế, kịch bản này là chính xác những gì được thực hiện trong thế giới thực rất thường xuyên với các công cụ dòng lệnh. – Robby75

+0

Một điều khác: Bạn nói rằng bạn không có tập tin po, điều đó có nghĩa là với một tập tin po trên đầu sẽ vẫn còn lớn hơn nhiều bởi vì nó sẽ phải phân tích/tìm kiếm/etc - để một tình huống tồi tệ nhất tồi tệ hơn; -) – Robby75

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