消除中间数组分配

  • Talk at RailsWorld: Presented about eliminating allocations in tokenizers and showed a function to measure allocations.

    • Allocation measurement function: def allocations; x = GC.stat(:total_allocated_objects); yield; GC.stat(:total_allocated_objects) - x; end
    • Examples of non-allocating code: Booleans, nil, symbols, integers, floats are represented as "tagged pointers" and don't allocate.
    • Examples of sometimes allocating code: Math on integers depends on the number size, and string literals depend on frozen_string_literal setting.
    • Examples of always allocating code: Arrays, hashes, objects, string slices, etc. allocate an object.
  • Shopify after-party question: RuboCop rule says to use [x, y].max for min or max calculations, but it seems wasteful as it allocates an array.

    • Compiler's perspective: Knows the array literal is ephemeral, allocates on the stack, does the calculation, and throws away the array.
    • Instruction sequence example: opt_newarray_send instruction is used, which checks for monkey patches and calls the appropriate max function.
    • Confirming no allocation: Using the allocations function shows the foo method doesn't allocate.
  • Aaron's Opinion Corner: Linter should explain why a rule is a rule. In this case, the performance-related rule may not be necessary as idiomatic Ruby is often performant. But there are cases where non-idiomatic code is needed for performance.
  • More Stuff: Array#max isn't the only method using this trick. It also works with Array#min, Array#pack, and Array#hash. But CRuby won't apply the optimization in all cases, like when there is a duparray instruction. Manually inlining simple cases like [3, 4].max to 4 is a workaround. These optimizations are context-dependent and prescribing more optimal code can be complex. Language servers can suggest faster code as a teaching opportunity.
阅读 8
0 条评论