Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

widgets.sidebar.toggle() causes incremental lag (js-debug-adapter) #1176

Open
serranomorante opened this issue Mar 23, 2024 · 7 comments
Open

Comments

@serranomorante
Copy link

serranomorante commented Mar 23, 2024

Debug adapter definition and debug configuration

Notice how toggling the sidebar gets more and more slow (I'm toggling it at a fast speed but it doesn't respond)

nvim-dap-sidebar-2024-03-23_21.54.13.webm

Debug adapter version

js-debug-adapter 1.95.0 (latest)
nvim nightly

Steps to Reproduce

Create and start a dummy react app (javascript)

npm create vite@latest vite-project -- --template react
cd vite-project
npm install
npm run dev

Reproduction steps on Neovim

  1. Copy my repro.lua code snippet and open nvim with nvim --clean +'so repro.lua' and wait for plugins to get automatically installed
  2. Install js-debug-adapter with MasonInstall js-debug-adapter
  3. Open the App.js file on vite-project/src/App.jsx
  4. Set a breakpoint on the return statement with lua require'dap'.toggle_breakpoint()
  5. Start the debugging session with :lua require'dap'.continue()
  6. Start toggling the sidebar with <leader>ds multiple times. Repeat this keymap until you notice the slow down.
-- DO NOT change the paths
local root = vim.fn.fnamemodify("./.repro", ":p")
root = root:sub(-1) == "/" and root or root .. "/"
-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. name
end

vim.g.mapleader = " "

--------------------------------------------------------------------------------

local plugins = {
  {
    "williamboman/mason.nvim",
    lazy = false,
    cmd = "Mason",
    opts = {
      ui = {
        check_outdated_packages_on_open = false,
        keymaps = {
          update_all_packages = "noop",
        },
      },
      install_root_dir = root .. "/mason",
    },
  },
  {
    "mfussenegger/nvim-dap",
    config = function()
      local dap = require("dap")
      local mason_registry = require("mason-registry")
      local vscode_js_debug_dap = mason_registry.get_package("js-debug-adapter")
      if vscode_js_debug_dap then
        local dap_executable = vscode_js_debug_dap:get_install_path() .. "/js-debug/src/dapDebugServer.js"

        for _, type in ipairs({
          "node",
          "chrome",
          "pwa-node",
          "pwa-chrome",
          "pwa-msedge",
          "node-terminal",
          "pwa-extensionHost",
        }) do
          local host = "localhost"
          dap.adapters[type] = {
            type = "server",
            host = host,
            port = "${port}",
            executable = {
              command = "node",
              args = { dap_executable, "${port}", host },
            },
          }
        end

        for _, language in ipairs({ "typescript", "javascript", "javascriptreact", "typescriptreact" }) do
          dap.configurations[language] = {
            {
              name = "Test react app",
              type = "pwa-chrome",
              request = "launch",
              url = "http://localhost:5173",
              webRoot = "${workspaceFolder}/vite-project",
              userDataDir = false,
              enableContentValidation = false, -- to make it work with vite HMR
            },
          }
        end
      end

      local widgets = require("dap.ui.widgets")
      local scopes_sidebar = widgets.sidebar(widgets.scopes, { number = true, wrap = false })
      vim.keymap.set("n", "<leader>ds", scopes_sidebar.toggle, { desc = 'DAP: Toggle "scopes" in sidebar' })
    end,
  },
}

--------------------------------------------------------------------------------

local lazypath = root .. "/plugins/lazy.nvim"
---@diagnostic disable-next-line: undefined-field
if not (vim.uv or vim.loop).fs_stat(lazypath) then
  vim.fn.system({
    "git",
    "clone",
    "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git",
    "--branch=stable",
    lazypath,
  })
end
vim.opt.runtimepath:prepend(lazypath)
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

Expected Result

Toggling shouldn't get more slow the more you execute it

Actual Result

Toggling the sidebar get more slow the more you use it

@serranomorante
Copy link
Author

This issue was mentioned on this discussion: #1171

@mfussenegger
Copy link
Owner

Looks like this might be a js-debug-adapter specific issue, see: microsoft/vscode-js-debug#2119

@serranomorante
Copy link
Author

Looks like this might be a js-debug-adapter specific issue, see: microsoft/vscode-js-debug#2119

Is it? I'm still able to reproduce it even after installing the vscode-js-debug commit that supposedly fixes the performance issue 😢

@mfussenegger
Copy link
Owner

Just had a closer look and seems like any slowdown in the adapter is indeed not the problem. toggling the scopes view doesn't re-request data, but just renders out the frame.

But I also can't reproduce it.
Is it possible that you have some sort of expensive WinEnter autocmd's or something like that setup that trigger each time?

You could try running something like:

require("jit.p").start("Fri2", "/tmp/profile")
for i = 1, 100 do
  vim.cmd("DapSidebar") -- adapt as needed to toggle the sidebar
  vim.cmd.redraw()
end
require("jit.p").stop()

To get some profiling data.

@mfussenegger mfussenegger changed the title [BUG]: widgets.sidebar.toggle() causes incremental lag (js-debug-adapter) widgets.sidebar.toggle() causes incremental lag (js-debug-adapter) Dec 6, 2024
@serranomorante
Copy link
Author

Thank you for further trying to fix this. Let me say I believe this issue is totally reproducible, at least by the steps I provided above (I just updated the description to use vite instead of create-react-app due to a recent bug on create-react-app, also updated the repro.lua to use vite's default port 5173).

This is the output I'm getting from your suggested snippet, let me know if you see anything strange:

Implementation

      local widgets = require("dap.ui.widgets")
      local scopes_sidebar = widgets.sidebar(widgets.scopes, { number = true, wrap = false })
      vim.keymap.set("n", "<leader>ds", function()
        require("jit.p").start("Fri2", "/tmp/profile")
        for i = 1, 100 do
          scopes_sidebar.toggle()
          vim.cmd.redraw()
        end
        require("jit.p").stop()
      end, { desc = 'DAP: Toggle "scopes" in sidebar' })

Result

33  repro.lua:75
5  ui.lua:render
3  _editor.lua:cmd
2  widgets.lua:456

Is it possible that you have some sort of expensive WinEnter autocmd's or something like that setup that trigger each time?

I'm using nvim --clean +'so repro.lua' so neither my own config nor my plugins are affecting the repro.

Can you revisit the repro steps?

simplescreenrecorder-2024-12-06_22.25.09.webm

@serranomorante
Copy link
Author

Maybe the sidebar buffer is too large? too many lines?
Maybe some of the buffer lines are too long?
Maybe the sidebar buffer highlights are slowing things down?

How can I disable all the highlights from that sidebar buffer to see if there's any improvement?

@serranomorante
Copy link
Author

serranomorante commented Dec 6, 2024

Using the same js-debug-adapter I tested with a different dap-scopes buffer (114 lines, not too much characters in the lines) and the problem doesn't happen 👍.

The issue seems to only happen with long dap-scopes buffers. From my video recording above, that buffer had more than 1k lines and the number of characters on some of those lines were also large.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants