1+ #!/usr/bin/env python
2+
3+ import asyncio
4+ import pyperf
5+ import os
6+ import logging
7+ from pathlib import Path
8+ from lsprotocol import types
9+
10+ from sqlmesh .lsp .custom import RenderModelRequest , RENDER_MODEL_FEATURE
11+ from sqlmesh .lsp .uri import URI
12+ from pygls .client import JsonRPCClient
13+
14+ # Suppress debug logging during benchmark
15+ logging .getLogger ().setLevel (logging .WARNING )
16+
17+
18+ class LSPClient (JsonRPCClient ):
19+ """A custom LSP client for benchmarking."""
20+
21+ def __init__ (self ):
22+ super ().__init__ ()
23+ self .render_model_result = None
24+ self .initialized = asyncio .Event ()
25+
26+ # Register handlers for notifications we expect from the server
27+ @self .feature (types .WINDOW_SHOW_MESSAGE )
28+ def handle_show_message (_ ):
29+ # Silently ignore show message notifications during benchmark
30+ pass
31+
32+ @self .feature (types .WINDOW_LOG_MESSAGE )
33+ def handle_log_message (_ ):
34+ # Silently ignore log message notifications during benchmark
35+ pass
36+
37+ async def initialize_server (self ):
38+ """Send initialization request to server."""
39+ # Get the sushi example directory
40+ sushi_dir = Path (__file__ ).parent .parent / "examples" / "sushi"
41+
42+ response = await self .protocol .send_request_async (
43+ types .INITIALIZE ,
44+ types .InitializeParams (
45+ process_id = os .getpid (),
46+ root_uri = URI .from_path (sushi_dir ).value ,
47+ capabilities = types .ClientCapabilities (),
48+ workspace_folders = [
49+ types .WorkspaceFolder (
50+ uri = URI .from_path (sushi_dir ).value ,
51+ name = "sushi"
52+ )
53+ ]
54+ )
55+ )
56+
57+ # Send initialized notification
58+ self .protocol .notify (types .INITIALIZED , types .InitializedParams ())
59+ self .initialized .set ()
60+ return response
61+
62+
63+ async def benchmark_render_model_async (client : LSPClient , model_path : Path ):
64+ """Benchmark the render_model request."""
65+ uri = URI .from_path (model_path ).value
66+
67+ # Send render_model request
68+ result = await client .protocol .send_request_async (
69+ RENDER_MODEL_FEATURE ,
70+ RenderModelRequest (textDocumentUri = uri )
71+ )
72+
73+ return result
74+
75+
76+ def benchmark_render_model (loops ):
77+ """Synchronous wrapper for the benchmark."""
78+ async def run ():
79+ # Create client
80+ client = LSPClient ()
81+
82+ # Start the SQLMesh LSP server as a subprocess
83+ await client .start_io ("python" , "-m" , "sqlmesh.lsp.main" )
84+
85+ # Initialize the server
86+ await client .initialize_server ()
87+
88+ # Get a model file to test with
89+ sushi_dir = Path (__file__ ).parent .parent / "examples" / "sushi"
90+ model_path = sushi_dir / "models" / "customers.sql"
91+
92+ # Warm up
93+ await benchmark_render_model_async (client , model_path )
94+
95+ # Run benchmark
96+ t0 = pyperf .perf_counter ()
97+ for _ in range (loops ):
98+ await benchmark_render_model_async (client , model_path )
99+ dt = pyperf .perf_counter () - t0
100+
101+ # Clean up
102+ await client .stop ()
103+
104+ return dt
105+
106+ return asyncio .run (run ())
107+
108+
109+ def main ():
110+ runner = pyperf .Runner ()
111+ runner .bench_time_func (
112+ "lsp_render_model" ,
113+ benchmark_render_model
114+ )
115+
116+
117+ if __name__ == "__main__" :
118+ main ()
0 commit comments