GNOME Bugzilla – Bug 499954
[ARITH] Key repeat is delayed
Last modified: 2008-04-12 08:23:07 UTC
Holding down a key in calculator stalls the display and uses up 100% CPU. Steps to reproduce: 1. Open Calculator 2. Hold down 1 key Expected result: 1s are continuously and smoothly appended to the display Actual result: The first few are added then the display stalls and 100% CPU is used. After ~1s many more numbers are shown (i.e. they were delayed) This doesn't occur in 2.20.2, occurs slightly in 2.22.1 and occurs in 2.22.0 and 2.22.2. Doing a ltrace of calctool shows many expensive repetitive operations (e.g. repeated strlen() of a 199 character 0.000000... string) but I can't see a major difference between this and the 2.20 series.
I tried reimplementing the make minimal changes to display routine to see if this was causing it but it made no difference (as I would expect since GTK+ is probably faster at just replacing the display).
Note that this is only a problem (for me at least) in arithmetic precedence mode, which suggests that the problem is going to be specific to a "case EXPRS:" clause somewhere.
Created attachment 100854 [details] Gprof results I recompiled gcalctool with the -p option to allow us to run gprof on it. I then did the following test: 1/ Start gcalctool Make sure you are in arithmetic precedence mode. 2/ Held the "3" down for about five seconds. 3/ Selected File->Quit from the menu bar. I then generated these results with: % gprof gcalctool gmon.out From a quick perusal of the results, I'd say that we are doing *way* too much validation of what the user is typing in as s/he is typing it in. Sami/Robert, perhaps you can pin-point how best to improve this. One possible "quick fix" is to make sure that we synchronously update the display area after processing each input character, that may make the problem look less obvious.
Found the problem. It's the bit panel that is causing the problem. Each key that gets pressed causes the display to be updated which means the bit panel needs to be updated. This occurs in gtk.c through set_bit_panel() in do_button(). As the display gets more complicated the calculation gets slower and slower. This occurs in all modes but the bit panel is only visible in scientific mode. The facts: 1. We have to update the bit panel when the number in the display is changed. There should be an optimisation that the bit panel is greyed out unless the display is an appropriately sized integer (i.e. if it has a fractional component ('1.123') or is a calculation('123+456')) 2. The arithmetic solver is too slow. The above example of entering a single repeating digit is a simple case and should not cause this much delay. 3. The bit panel should not be set from the UI. It currently gets updated when a button is pressed but should be updated when the display changes (which can be caused by other events like mode changes). Sami, can you look at the parser/solver and see why it is so slow solving simple integers?
(to prove it is the bit panel quote out the set_bit_panel() call and recompile)
>2. The arithmetic solver is too slow. The above example of entering a single >repeating digit is a simple case and should not cause this much delay. Can you give some details? I left "int ret = usable_num(MP);" into set_bit_panel() and commented the whole "switch" section out. After that, the slowness was gone.
Yes, but you've deleted the bin_str() call which is only in the EXPRS branch of set_bit_panel()...
Expanding the scope beyond the parser. The bin_str() uses mp lib which might be slow. I suggest using the same method in expression mode than is used in non-expression mode. That is, replacing EXPRS branch with: ----- code in EXPR case ------- if (ret || !is_integer(MP)) { gtk_widget_set_sensitive(X->bit_panel, FALSE); return; } { char *bit_str, label[3], tmp[MAXLINE]; bit_str = make_fixed(MP, tmp, BIN, MAXLINE, FALSE); bit_str_len = strlen(bit_str); if (bit_str_len <= MAXBITS) { gtk_widget_set_sensitive(X->bit_panel, TRUE); STRCPY(label, " 0"); for (i = 0; i < MAXBITS; i++) { label[1] = (i < bit_str_len) ? bit_str[bit_str_len-i-1] : '0'; gtk_label_set_text(GTK_LABEL(X->bits[MAXBITS - i - 1]), label); } return; } } --- end of code --- This seems to make it fast. I'll add this to my TODO list and write a real patch when I get a moment for that.
Created attachment 101491 [details] [review] Faster implementation for creating binary numbers
Please note that there still is a bug, which is caused by the is_integer() call. is_integer() is not able to detect, for example, 2^8 as an integer.
Patch committed. Thanks. > Please note that there still is a bug, which is caused by the is_integer() > call. is_integer() is not able to detect, for example, 2^8 as an integer. Can you provide a set of steps that I can do with gcalctool that reproduces this problem?
Problem doesn't seem to occur in 2.22.1, closing.