emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Inefficiency in Bgotoifnil byte-code instruction


From: John Wiegley
Subject: Inefficiency in Bgotoifnil byte-code instruction
Date: Wed, 27 Jun 2012 22:01:52 -0500
User-agent: Gnus/5.130006 (Ma Gnus v0.6) Emacs/24.1 (darwin)

I've been doing some byte-code profiling, and have discovered that the opcodes
Bgotoifnil and Bgotoifnonnil are high up, in the top ten:

    | Bcall+3       |  1228846 | 21464419 | 21.464 |
    | Bcall+1       | 15379936 | 17113001 | 17.113 |
    | Bcall         |   895713 | 15189629 |  15.19 |
    | Bcall+6       |   105234 |  6720697 | 6.7207 |
    | Bcall+2       |  5616918 |  6043517 | 6.0435 |
    | Bgotoifnil    | 43048427 |  4416549 | 4.4165 |
    | Bvarref+6     | 63539569 |  3507246 | 3.5072 |
    | Bgotoifnonnil | 24043617 |  2474823 | 2.4748 |
    | Bgoto_char    |   517466 |  1867576 | 1.8676 |
    | Bcar          | 32846356 |  1741051 | 1.7411 |

My recommendation is that we split these into two ops: Bgotoifnil and
Bgotoifnonnil, which use only FETCH and a positive/negative offset from the
current pc, and Bgotoifnil2 and Bgotoifnonnil2 which use the old logic
(FETCH2, and an absolute offset from the start of the bytecode stream).

The resulting interpreter code would look like this:

    #ifdef BYTE_CODE_SAFE
    #define CHECK_OFFSET_RANGE(ARG)                                \
      {                                                            \
        int curpos = start.pc - stack.byte_string_start;           \
                                                                   \
        if (curpos + ARG >= bytestr_length || curpos + ARG < 0)    \
          abort ()                                                 \
      }
    #else /* not BYTE_CODE_SAFE */
    #define CHECK_OFFSET_RANGE(ARG)
    #endif /* not BYTE_CODE_SAFE */

        case Bgotoifnil:
          {
            Lisp_Object v1;
            MAYBE_CG ();
            op = FETCH;
            v1 = POP;
            if (NILP (v1))
              {
                BYTE_CODE_QUIT;
                CHECK_OFFSET_RANGE (op);
                stack.pc += op;
              }
            break;
          }

        case Bgotoifnil2:
          {
            Lisp_Object v1;
            MAYBE_GC ();
            op = FETCH2;
            v1 = POP;
            if (NILP (v1))
              {
                BYTE_CODE_QUIT;
                CHECK_RANGE (op);
                stack.pc = stack.byte_string_start + op;
              }
            break;
          }

        /* and likewise for Bgotoifnonnil... */

This way we optimize for the most used case for such a common instruction.

Making this change in the C code is easy, but changing bytecomp.el wasn't
obvious to me.  Can anyone help me with that?

John



reply via email to

[Prev in Thread] Current Thread [Next in Thread]