I have tested the 13900K+3090, 7950x+4090, and 7950x3d+4090, and there is a serious issue with Canvas performance. No configuration can smoothly run a Canvas card with 26,000 characters of content

In this post,For heavy Canvas users (from hundreds of thousands to millions of words), which computer components should be upgraded?

I have described the problems I encountered and tried some methods, but none improved the situation. So, I thought about testing using a remote computer rented online.

Why the coherence of the cards and side-by-side display is so important, and why I think a two-dimensional note like Canvas is more important than Markdown. To gain inspiration by displaying information and its relevance within a limited space.

Platforms:

  • 7950X
    • Configuration:
      • CPU: 7950X
      • Memory: Kingbank DDR5-6000 64GB (shows 4800Mhz on Windows)
      • Graphics Card: RTX 4090
      • System: Win10
    • Benchmarks:
    • PS: Remote desktop + Task Manager + HWinfo64. The first time using OSB to record, the window selection was wrong, and the recording was not successful.
  • 7950X3D
  • 13900K

Testing methods:

  • With plugins enabled and disabled
    • Single-core test: Input into a card in Chinese, English, and LaTeX. Observe Core Usage in Task Manager and HWinfo.
    • Multi-core test: Use the right mouse button to move the Canvas, loading multiple cards to test multi-core (only two threads working).

Test results:

  • 7950X+4090+DDR5 4800

    • Due to the first test, the recording was not successful, and the testing method was not well planned (plugins were not disabled).
    • Conclusion:
      • Editing a 27,000-character card causes noticeable input lag, with Chinese < English < LaTeX.
      • Dragging the page is laggy.
  • 7950X3D+4090+DDR5 3600

    • With plugins enabled:

    • With plugins disabled:

  • 13900K+3090+DDR4 3200

    • With plugins enabled:

      • Dragging the page, two cores reach a usage of 116.4%, 115.8%, the lag is perceptibly the same as the 7950X3D.

      • Inputting content, one core reaches a usage of 158.4, slightly better than the 7950X3D.

    • With plugins disabled:

      • Dragging the page, two cores reach a usage of 110.1%, 154.4%, the lag is the same.

      • Inputting content, everything but LaTeX is good.

Conclusion:

  • Which hardware improves Canvas performance:

    • Graphics Card (almost no improvement, my test platforms were all 4090, 3090)
    • Memory (did not feel an improvement)
    • CPU, single-core performance or single-thread performance (very important)
  • Test results:

    • Canvas has almost no multi-core optimization, at most two cores work.
    • The graphics card hardly works. During dragging and writing content, the graphics card does not work (because I used a remote desktop, so the graphics card usage is mainly due to the remote desktop software). On my own computer, the 3060 hardly works.
    • The main reason for Canvas lag is the CPU single-core usage exceeding 100%.
    • The same number of characters in a markdown document does not cause lag, but it does on a Canvas page, suggesting that markdown has block content rendering, and Canvas has serious optimization issues.
    • Plugins affect the smooth experience of Canvas, especially Latex-suite 1.7.4 (because we need to automatically enter & under $$ with tab, so we updated to the latest), even if you do not edit LaTeX content, it will cause lag with 26,000 characters (the main reason, disabling plugins can edit smoothly)
    • There is not much difference between AMD and Intel, at least at the user perception level, X3D does not improve.
    • It may be related to memory
      • When I used the 5800x, the CPU was not fully loaded when dragging, but when I used the 13900 with 2400 memory, the single core was still full, that is, it exceeded 100% in HWinfo64.

Suggestions:

  • Add hardware acceleration features, don’t let the graphics card idle, let it help with the rendering and editing of markdown.
  • Add multi-threading support
    • First, allocate different threads to multiple cards to improve multi-core utilization.
    • Second, support partitioning of individual cards to reduce the burden on a single core.
  • Optimize LaTeX, whether plugins are enabled or disabled, inputting LaTeX causes severe lag.
  • Convert cards into markdown documents.
    • Due to limited rental time, I did not test whether Markdown cards in Canvas would perform better. I will upload the video after I have edited it.
6 Likes

Update Content - Video

  • 7950X3D+4090+DDR5 3600

    • With plugin enabled dragging
  • With plugin enabled inputting
  • With plugin disabled dragging
  • With plugin disabled inputting
  • 13900K+3090+DDR4 3200

    • With plugin enabled dragging and inputting
  • With plugin disabled dragging
  • With plugin disabled inputting

This is true. Canvas has a really bad performance with many notes.
Can I ask you to make the same test with the Excalidraw plugin?

1 Like

It might be possible, but I would need you to provide the files. However, I may only have a 14900K computer because I pay out of pocket to rent computers for testing. Later, I want to try @demeneer’s snippet method. Although this method has shown a slight improvement on my 3700x+3060, it still hasn’t resolved the experience issues, and it’s not yet usable for normal operations.

This css snippet is very useful, can you enable it and test it again?

The problem still lies in the fact that when there is too much content on the page, the processing methods of Canvas cards and Markdown are different. Canvas likely doesn’t render in chunks. This issue is particularly noticeable when cards are aligned side by side. You can try to adjust your canvas’s display ratio to be as small as possible and still visible (pull to the right). The main problem is that Canvas has not been well optimized for multicore and hardware acceleration, leading to a heavy reliance on single-core performance. This snippet cannot solve the editing issue, as I mentioned above, one is editing, and the other is dragging. Therefore, the chances of improvement are very low, as this is essentially a performance optimization issue of Canvas not being able to support a card with tens of thousands of words. I will try it tomorrow or the day after, but based on the above conclusion, even if there is an improvement, it will only be in the dragging process, not the editing process

No, it’s not working. I’ve tried for half an hour and can’t copy my file into the Excalidraw plugin. If I copy it alone, it’s not in markdown format. So you’d better provide a file with similar content for me. However, I’m about to test soon.

Update: New Test Content

Test Update Content:

  1. Whether @demeneer’s snippet script is effective.
.view-content:has(> .canvas-wrapper) {
  overflow: hidden;
}

.canvas-wrapper {
  width: 1000%;
  height: 1000%;

  left: -450%;
  top: -450%;

  .canvas {

    transition: transform 60ms ease;
    will-change: transform, scale, translate;

    > svg * {
      shape-rendering: optimizeSpeed;
    }
  }

  .canvas-controls {
    right: calc(45% + var(--size-4-2));
    top: calc(45% + var(--size-4-2));
  }

  .canvas-card-menu {
    bottom: calc(45% + var(--size-4-2));
  }
}
  1. Whether importing markdown into Canvas to replace cards will improve performance.
  2. Excalidraw testing.
  3. Testing the effects after disabling several main plugins.

Conclusion:

  • Demeneer’s script does not improve drag-and-drop page and input performance in this test environment. It also causes user interface flickering and card display issues, and does not alleviate CPU single-core performance overload.
  • Importing markdown files into Canvas to replace cards does not improve efficiency. However, the same content in markdown is very smooth even with plugins enabled.
  • Importing markdown into Excalidraw and canvas does not optimize performance.
  • Disabling latex-suite 1.7.4 and Easy-typing improves input performance when plugins are enabled.

Test Platform:

  • 14900K+4090+DDR5 6000
  • Benchmark Scores:
    • CPU-Z
      • Single-core: 915
      • Multi-core: 16677.3
    • Geekbench
      • ASUS System Product Name - Geekbench

Videos:

  • Video 1: Drag-and-drop and input performance test with plugins enabled and disabled under snippet.
  • Video 2: Drag-and-drop and input performance test with plugins enabled under disabled snippet.
  • Video 3: Drag-and-drop and input performance test with plugins disabled under disabled snippet.
1 Like

If there are more than a hundred images in the canvas, the canvas may crash, and the scaling will be very laggy.

After enabling this CSS snippet, the canvas will better than before.(This is my experience using it)

In addition, I canceled the shadow and rounded corners of the canvas card through css to slightly improve performance.

I think it’s related to the usage environment, as my cards contain a lot of text and LaTeX. Moreover, I’ve set the card display to the minimum limit. As you can see in the video above, enabling the CSS snippet causes window flickering, and it doesn’t change the CPU overload situation. I’m now trying to use the developer tools’ performance feature to detect more specific time usage. However, I’ve encountered an export issue and can’t export the report. ‘Failed to save timeline: The request is not allowed by the user agent or the platform in the current context. (NotAllowedError)’

I’ve found a pretty good alternative method. It involves converting cards into markdown files, which allows us to edit cards in markdown without significant lag. I would like to recommend the plugin at GitHub - slnsys/obsidian-canvas2document: Plugin for Obsidian to convert a complete Canvas to a long form document. It’s excellent for converting cards into markdown files. Currently, it hasn’t been updated to sync to the canvas, but the developer has stated that this feature will be included in the next few updates. I’m very grateful for this plugin.Now released 1.2.0 of Canvas2Document with full support of complex hierarchical structures, ordering and metadata for navigation

By the way, @WhiteNoise, do we have any plans for canvas performance optimization at the moment? Or is there any specific test that I need to provide?

Script: Pair with Obsidian Canvas2Document to automatically convert canvas replacement cards into markdown files.

import json
import os

def find_obsidian_root(current_dir):
    # Search upwards from the current directory until the root directory containing the .obsidian folder is found
    while True:
        if os.path.exists(os.path.join(current_dir, '.obsidian')):
            return current_dir
        # Get the parent directory of the current directory
        current_dir = os.path.dirname(current_dir)
        # Stop searching if the root directory is reached
        if current_dir == os.path.dirname(current_dir):
            raise FileNotFoundError("Could not find the root directory containing the .obsidian folder")

def load_canvas_data(file_path):
    with open(file_path, 'r', encoding='utf-8') as file:
        return json.load(file)

def save_canvas_data(file_path, data):
    with open(file_path, 'w', encoding='utf-8') as file:
        json.dump(data, file, ensure_ascii=False, indent=4)

def update_modified_canvas_with_new_nodes(original_canvas, modified_canvas, base_path, relative_base_path, obsidian_root):
    modified_node_ids = {node["id"] for node in modified_canvas.get("nodes", [])}
    for node in original_canvas.get("nodes", []):
        if node["id"] not in modified_node_ids:
            print(f"Syncing new node: {node}")
            if node.get("type") == "text":
                node_id = node["id"]
                new_file_path = os.path.join(base_path, f"newdoc-node_{node_id}_fromCanvas.md").replace("\\", "/")

                # Create the markdown file and copy content if it does not exist
                if not os.path.exists(new_file_path):
                    with open(new_file_path, 'w', encoding='utf-8') as md_file:
                        md_file.write(node["text"])

                node["type"] = "file"
                node["file"] = os.path.relpath(new_file_path, obsidian_root).replace("\\", "/")
                del node["text"]
                
                print(f"Synced node: {node}")
            
            modified_canvas["nodes"].append(node)

def replace_canvas_content():
    # Get the directory of the script
    script_dir = os.path.dirname(os.path.abspath(__file__))
    print(f"Script directory: {script_dir}")
    
    # Find the root directory containing the .obsidian folder
    obsidian_root = find_obsidian_root(script_dir)
    print(f"Found .obsidian root directory: {obsidian_root}")
    
    # Get all .canvas files in the script directory
    canvas_files = [f for f in os.listdir(script_dir) if f.endswith('.canvas') and not f.endswith('_modified.canvas')]
    print(f"Found .canvas files: {canvas_files}")

    for canvas_file in canvas_files:
        modified_canvas_file = canvas_file.replace('.canvas', '_modified.canvas')
        
        # Skip processing if the modified file exists
        if os.path.exists(os.path.join(script_dir, modified_canvas_file)):
            print(f"Found modified file: {modified_canvas_file}, skipping {canvas_file}")
            continue

        print(f"\nProcessing file: {canvas_file}")
        
        canvas_file_path = os.path.join(script_dir, canvas_file).replace("\\", "/")
        base_name = os.path.splitext(canvas_file)[0]
        base_path = os.path.join(script_dir, f"{base_name}_canvas2doc-data").replace("\\", "/")
        
        # Skip processing if the corresponding folder does not exist
        if not os.path.exists(base_path):
            print(f"Warning: Folder {base_path} does not exist, skipping {canvas_file}")
            continue
        
        # Read the contents of the canvas file
        canvas_data = load_canvas_data(canvas_file_path)
        print(f"Read file content: {canvas_data}")

        # Calculate the relative path
        relative_base_path = os.path.relpath(base_path, obsidian_root).replace("\\", "/")
        print(f"Relative folder path: {relative_base_path}")

        # Iterate through each node in the canvas file and replace content
        for node in canvas_data.get("nodes", []):
            print(f"Processing node: {node}")
            
            if node.get("type") == "text":
                node_id = node["id"]
                new_file_path = os.path.join(base_path, f"newdoc-node_{node_id}_fromCanvas.md").replace("\\", "/")

                # Create the markdown file and copy content if it does not exist
                if not os.path.exists(new_file_path):
                    with open(new_file_path, 'w', encoding='utf-8') as md_file:
                        md_file.write(node["text"])

                node["type"] = "file"
                node["file"] = os.path.relpath(new_file_path, obsidian_root).replace("\\", "/")
                # Delete the original "text" field
                del node["text"]
                
                print(f"Modified node: {node}")

        # Save the modified content back to a new canvas file
        modified_canvas_file_path = os.path.join(script_dir, modified_canvas_file).replace("\\", "/")
        save_canvas_data(modified_canvas_file_path, canvas_data)

        print(f"Content successfully replaced and saved to: {modified_canvas_file_path}")

    # Process all _modified.canvas files
    modified_canvas_files = [f for f in os.listdir(script_dir) if f.endswith('_modified.canvas')]
    for modified_canvas_file in modified_canvas_files:
        print(f"\nProcessing modified file: {modified_canvas_file}")
        
        modified_canvas_file_path = os.path.join(script_dir, modified_canvas_file).replace("\\", "/")
        base_name = modified_canvas_file.replace('_modified.canvas', '')
        base_path = os.path.join(script_dir, f"{base_name}_canvas2doc-data").replace("\\", "/")
        original_canvas_file_path = os.path.join(script_dir, f"{base_name}.canvas").replace("\\", "/")

        # Read the contents of the modified canvas file
        modified_canvas_data = load_canvas_data(modified_canvas_file_path)
        original_canvas_data = load_canvas_data(original_canvas_file_path)
        print(f"Read file content: {modified_canvas_data}")

        # Calculate the relative path
        relative_base_path = os.path.relpath(base_path, obsidian_root).replace("\\", "/")
        print(f"Relative folder path: {relative_base_path}")

        # Sync new nodes
        update_modified_canvas_with_new_nodes(original_canvas_data, modified_canvas_data, base_path, relative_base_path, obsidian_root)

        # Iterate through each node in the modified canvas file and replace content
        for node in modified_canvas_data.get("nodes", []):
            print(f"Processing node: {node}")
            
            if node.get("type") == "text":
                node_id = node["id"]
                new_file_path = os.path.join(base_path, f"newdoc-node_{node_id}_fromCanvas.md").replace("\\", "/")
                
                # Write the text content to a new markdown file
                if not os.path.exists(new_file_path):
                    with open(new_file_path, 'w', encoding='utf-8') as md_file:
                        md_file.write(node["text"])

                node["type"] = "file"
                node["file"] = os.path.relpath(new_file_path, obsidian_root).replace("\\", "/")
                # Delete the original "text" field
                del node["text"]
                
                print(f"Modified node: {node}")

        # Save the modified content back to the modified canvas file
        save_canvas_data(modified_canvas_file_path, modified_canvas_data)

        print(f"Content successfully replaced and saved to: {modified_canvas_file_path}")

# Run the script
replace_canvas_content()

Hi, thank you for your testing, I have same problem when dragging the canvas (not too large). Hope Obsidian team will fix this issue in future update.

Thanks for your extensive efforts.

Better Canvas Performance should be on team’s roadmap imho.
Otherwise it’ll be hard to get excited for new features, when we know they’ll be abandoned like this.

If that’s the case, you can try the script mentioned above. This script improves performance when the content isn’t too extensive. My main issue is that each card contains thousands or even tens of thousands of words. I’ve even noticed that editing with Markdown documents is becoming a bit laggy.

.view-content:has(> .canvas-wrapper) {
  overflow: hidden;
}

.canvas-wrapper {
  width: 1000%;
  height: 1000%;

  left: -450%;
  top: -450%;

  .canvas {

    transition: transform 60ms ease;
    will-change: transform, scale, translate;

    > svg * {
      shape-rendering: optimizeSpeed;
    }
  }

  .canvas-controls {
    right: calc(45% + var(--size-4-2));
    top: calc(45% + var(--size-4-2));
  }

  .canvas-card-menu {
    bottom: calc(45% + var(--size-4-2));
  }
}

Haha, compared to their (the Obsidian team’s) selfless contributions, I’m still far behind. Yes, I’m now completely using the canvas as a blackboard, and it’s really great to use it with LaTeX, except for some issues with performance and references.
:face_with_peeking_eye: :face_with_peeking_eye:

Update Performance Report, Drag Behavior Report, and Input Behavior Report.

Enable pulg-ins

inputting.part01.zip (3 MB)
inputting.part02.zip (2.5 MB)

dragging.part01.zip (3 MB)
dragging.part02.zip (1.1 MB)

disable plug-ins

disalbe-dragging.zip (1.5 MB)

disable-inputting.part01.zip (3 MB)
disable-inputting.part02.zip (3 MB)
disable-inputting.part03.zip (131.7 KB)

SYSTEM INFO:
Obsidian version: v1.6.7
Installer version: v1.6.7
Operating system: Windows 10 Enterprise 10.0.19045
Login status: not logged in
Insider build toggle: off
Live preview: on
Base theme: dark
Community theme: Blue Topaz v2023111501
Snippets enabled: 6
Restricted mode: off
Plugins installed: 55
Plugins enabled: 26
1: Advanced URI v1.40.1
2: Edit History v0.1.3
3: Linter v1.24.0
4: Paste URL into selection v1.7.0
5: Remember cursor position v1.0.8
6: Settings Search v1.3.10
7: Tag Wrangler v0.6.1
8: Version History Diff v2.2.0
9: Style Text v0.1.0
10: Paste As Html v1.0.2
11: Chronology v1.1.11
12: Custom Attachment Location v0.0.9
13: List Callouts v1.2.7
14: Excalidraw v2.1.6
15: BRAT v1.0.1
16: Canvas Block Reference v0.0.4
17: Style Settings v1.0.8
18: Extract url content v0.12.1
19: Auto Link Title v1.5.4
20: Latex Suite v1.7.4
21: Update time on edit v2.4.0
22: Annotator v0.2.11
23: Dataview v0.5.66
24: Easy Typing v5.3.2
25: Highlightr v1.2.2
26: Canvas2Document v1.1.0

Ok, I am gonna move this to the help section, as performance problems are not bugs per se. You can open a Feature Request asking to improve the performance on large canvas.

Two things I noticed in your screen recording.

  1. you keep multiple long notes completely unrolled in view. That’s really taxing.
  2. It doesn’t look like you you using the “Zoom threshold for hiding card content” optimization at all.

We are aware that there is a bug when panning in and out in a region where there is a large number of nodes and that is going to be addressed.

Thank you for your reply. Over the past few days, I have tested a few things and found the following:

  1. Reinstalling Obsidian can bring some performance improvements (while also deleting AppData\Local\Programs\obsidian and AppData\Roaming\obsidian). However, in my previous tests on a remote computer, I only copied the vault, and the situation remained the same. I guess the new version might have updated some performance features?
  2. Assigning Obsidian to the integrated graphics, for example, through the graphics settings page (the one that allows using hardware-accelerated GPU scheduling), and assigning Obsidian to the integrated graphics. These two methods do not significantly improve the canvas but greatly optimize markdown editing. The former makes writing smoother, and the latter prevents freezing when quickly scrolling through markdown notes. Actually, I am also puzzled why my 3060 freezes, but the integrated graphics perform very well. It might be due to bandwidth or other reasons? I have tried completely reinstalling the drivers, but it didn’t help much.

As for why I don’t use the “Zoom threshold for hiding card content,” it’s because I need these cards to be displayed to facilitate my thinking and separately record ideas. This is also why I have always advocated for using canvas for two-dimensional nonlinear note-taking.