continue icon indicating copy to clipboard operation
continue copied to clipboard

perf(llm): Optimize pruneLines functions in countTokens

Open 0x23d11 opened this issue 6 months ago • 4 comments

Description

Closes #4947

This PR addresses issue #4947 by optimizing the performance of the pruneLinesFromTop and pruneLinesFromBottom functions in core/llm/countTokens.ts

Problem

The previous implementations used Array.prototype.shift() and Array.prototype.pop() within a while loop to remove lines from the beginning or end of a prompt until it fit within the token limit. These array modification methods have a time complexity of O(n) because they require shifting subsequent elements. When dealing with very long prompts (e.g., thousands of lines), repeatedly calling shift() or pop() becomes computationally expensive, leading to significant performance degradation.

Solution

The implemented solution refactors these functions to avoid costly array modifications within the loop:

  1. The prompt is split into lines.
  2. The token count for each line is calculated once upfront and stored in an array (lineTokens).
  3. The total initial token count is calculated by summing lineTokens and adding the count for necessary newline characters (\n).
  4. A while loop iterates as long as the totalTokens exceeds maxTokens.
  5. Inside the loop, instead of removing elements from the lines array, an index pointer (start or end) is adjusted.
  6. The pre-calculated token count for the line being (conceptually) removed, along with its corresponding newline token, is subtracted from totalTokens.
  7. After the loop, Array.prototype.slice() (an O(n) operation performed only once) is used with the final start or end index to extract the desired lines.
  8. The resulting lines are joined back into a string.

Benefits

This approach drastically reduces the computational complexity, especially for large prompts, as the expensive O(n) operations (shift/pop) inside the loop are replaced by cheap O(1) index increments/decrements. The token calculation per line and the final slice operation are performed only once.

Checklist

  • [x] I've read the contributing guide
  • [] The relevant docs, if any, have been updated or created
  • [] The relevant tests, if any, have been updated or created

Screenshots

[ For visual changes, include screenshots. Screen recordings are particularly helpful, and appreciated! ]

Testing instructions

[ For new or modified features, provide step-by-step testing instructions to validate the intended behavior of the change, including any relevant tests to run. ]

0x23d11 avatar Apr 23 '25 12:04 0x23d11