snapshot 2025-04-21 01:01:17.676650
This commit is contained in:
		
							parent
							
								
									43994667f4
								
							
						
					
					
						commit
						e21979baf0
					
				
							
								
								
									
										488
									
								
								console-export-2025-4-19_17-21-48.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										488
									
								
								console-export-2025-4-19_17-21-48.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,488 @@ | ||||
| GET | ||||
| https://www.speedscope.app/ | ||||
| [HTTP/2 304  70ms] | ||||
| 
 | ||||
| GET | ||||
| https://www.speedscope.app/speedscope-GHPHNKXC.css | ||||
| [HTTP/3 200 OK 0ms] | ||||
| 
 | ||||
| GET | ||||
| https://www.speedscope.app/speedscope-YI5LLI47.js | ||||
| [HTTP/3 200  0ms] | ||||
| 
 | ||||
| GET | ||||
| https://www.speedscope.app/chunk-JFPBPGZ4.js | ||||
| [HTTP/3 200  0ms] | ||||
| 
 | ||||
| GET | ||||
| https://www.speedscope.app/source-map-5DQ363YZ.js | ||||
| [HTTP/3 200  0ms] | ||||
| 
 | ||||
| GET | ||||
| https://www.speedscope.app/chunk-FW4363Y4.js | ||||
| [HTTP/3 200  0ms] | ||||
| 
 | ||||
| GET | ||||
| https://www.speedscope.app/SourceCodePro-Regular.ttf-ILST5JV6.woff2 | ||||
| [HTTP/3 200  0ms] | ||||
| 
 | ||||
| GET | ||||
| https://www.speedscope.app/demangle-B53S5JWH.js | ||||
| [HTTP/3 200  0ms] | ||||
| 
 | ||||
| GET | ||||
| https://www.speedscope.app/import-2JMDXOIJ.js | ||||
| [HTTP/3 200  0ms] | ||||
| 
 | ||||
| speedscope v1.22.2 speedscope-YI5LLI47.js:185:25290 | ||||
| WebGL initialized. renderer: null, vendor: null, version: WebGL 1.0 speedscope-YI5LLI47.js:167:1925 | ||||
| GET | ||||
| https://www.speedscope.app/favicon-16x16-VSI62OPJ.png | ||||
| [HTTP/3 200  0ms] | ||||
| 
 | ||||
| Importing as speedscope json file import-2JMDXOIJ.js:4:35604 | ||||
| import: 0ms - timer ended speedscope-YI5LLI47.js:185:18554 | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     draw graphics.ts:449 | ||||
|     render rectangle-batch-renderer.ts:140 | ||||
|     writeToAtlasIfNeeded row-atlas.ts:70 | ||||
|     dt utils.ts:19 | ||||
|     writeToAtlasIfNeeded row-atlas.ts:59 | ||||
|     render flamechart-renderer.ts:323 | ||||
|     renderRects flamechart-minimap-view.tsx:88 | ||||
|     setViewport canvas-context.ts:72 | ||||
|     renderBehind canvas-context.ts:85 | ||||
|     renderRects flamechart-minimap-view.tsx:87 | ||||
|     onBeforeFrame flamechart-minimap-view.tsx:223 | ||||
|     onBeforeFrame canvas-context.ts:63 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-minimap-view.tsx:228 | ||||
|     overlayCanvasRef flamechart-minimap-view.tsx:419 | ||||
|     Preact 76 | ||||
|     a atom.ts:149 | ||||
|     set atom.ts:120 | ||||
|     set atom.ts:120 | ||||
|     set profile-group.ts:62 | ||||
|     setProfileGroup profile-group.ts:71 | ||||
|     loadProfile application.tsx:225 | ||||
|     loadFromFile application.tsx:234 | ||||
|     onFileSelect application.tsx:466 | ||||
|     Preact 23 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: texImage: Requested size at this level is unsupported. | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| The resource at “https://www.speedscope.app/SourceCodePro-Regular.ttf-ILST5JV6.woff2” preloaded with link preload was not used within a few seconds. Make sure all attributes of the preload tag are set correctly. www.speedscope.app | ||||
| Source map error: Error: URL constructor:  is not a valid URL. | ||||
| Stack in the worker:resolveSourceMapURL@resource://devtools/client/shared/source-map-loader/utils/fetchSourceMap.js:56:22 | ||||
| getOriginalURLs@resource://devtools/client/shared/source-map-loader/source-map.js:73:24 | ||||
| workerHandler/</<@resource://devtools/client/shared/worker-utils.js:115:52 | ||||
| workerHandler/<@resource://devtools/client/shared/worker-utils.js:113:13 | ||||
| 
 | ||||
| Resource URL: wasm:https://www.speedscope.app/demangle-B53S5JWH.js%20line%201%20%3E%20WebAssembly.instantiate | ||||
| Source Map URL: null | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     (Async: FrameRequestCallback) | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
| WebGL warning: checkFramebufferStatus: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0: Attachment has no width or height. | ||||
| After reporting 32, no further warnings will be reported for this WebGL context. | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| 52 speedscope-YI5LLI47.js:1:25317 | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     (Async: FrameRequestCallback) | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseMove flamechart-pan-zoom-view.tsx:685 | ||||
|     Preact 31 | ||||
| Uncaught Error: Assertion failed. | ||||
|     H graphics.ts:34 | ||||
|     get framebuffer graphics.ts:1379 | ||||
|     _updateRenderTargetAndViewport graphics.ts:574 | ||||
|     clear graphics.ts:501 | ||||
|     onBeforeFrame canvas-context.ts:60 | ||||
|     requestFrame canvas-context.ts:53 | ||||
|     renderCanvas flamechart-pan-zoom-view.tsx:526 | ||||
|     onMouseLeave flamechart-pan-zoom-view.tsx:691 | ||||
|     Preact 31 | ||||
| speedscope-YI5LLI47.js:1:25317 | ||||
							
								
								
									
										386
									
								
								examples/connectivity.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										386
									
								
								examples/connectivity.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,386 @@ | ||||
| from collections.abc import Sequence | ||||
| from collections import defaultdict | ||||
| from pprint import pformat | ||||
| import logging | ||||
| 
 | ||||
| import numpy | ||||
| from numpy.typing import NDArray, ArrayLike | ||||
| import pyclipper | ||||
| from pyclipper import ( | ||||
|     Pyclipper, PT_CLIP, PT_SUBJECT, CT_UNION, CT_INTERSECTION, PFT_NONZERO, PFT_EVENODD, | ||||
|     scale_to_clipper, scale_from_clipper, PyPolyNode, | ||||
|     ) | ||||
| from masque.file import oasis, gdsii | ||||
| 
 | ||||
| from masque import Pattern | ||||
| from masque.shapes import Polygon | ||||
| from masque.utils import poly_contains_points | ||||
| 
 | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
| 
 | ||||
| 
 | ||||
| layer_t = tuple[int, int] | ||||
| contour_t = list[tuple[int, int]] | ||||
| net_name_t = str | object | ||||
| 
 | ||||
| 
 | ||||
| CLIPPER_SCALE_FACTOR = 2**24 | ||||
| 
 | ||||
| 
 | ||||
| def poly_contains_points2( | ||||
|         vertices: ArrayLike, | ||||
|         points: ArrayLike, | ||||
|         include_boundary: bool = True, | ||||
|         ) -> NDArray[numpy.int_]: | ||||
|     """ | ||||
|     Tests whether the provided points are inside the implicitly closed polygon | ||||
|     described by the provided list of vertices. | ||||
| 
 | ||||
|     Args: | ||||
|         vertices: Nx2 Arraylike of form [[x0, y0], [x1, y1], ...], describing an implicitly- | ||||
|             closed polygon. Note that this should include any offsets. | ||||
|         points: Nx2 ArrayLike of form [[x0, y0], [x1, y1], ...] containing the points to test. | ||||
|         include_boundary: True if points on the boundary should be count as inside the shape. | ||||
|             Default True. | ||||
| 
 | ||||
|     Returns: | ||||
|         ndarray of booleans, [point0_is_in_shape, point1_is_in_shape, ...] | ||||
|     """ | ||||
|     points = numpy.asarray(points) | ||||
|     vertices = numpy.asarray(vertices) | ||||
| 
 | ||||
|     if points.size == 0: | ||||
|         return numpy.zeros(0) | ||||
| 
 | ||||
|     min_bounds = numpy.min(vertices, axis=0)[None, :] | ||||
|     max_bounds = numpy.max(vertices, axis=0)[None, :] | ||||
| 
 | ||||
|     trivially_outside = ((points < min_bounds).any(axis=1) | ||||
|                        | (points > max_bounds).any(axis=1)) | ||||
| 
 | ||||
|     nontrivial = ~trivially_outside | ||||
|     if trivially_outside.all(): | ||||
|         inside = numpy.zeros_like(trivially_outside, dtype=bool) | ||||
|         return inside | ||||
| 
 | ||||
|     ntpts = points[None, nontrivial, :]     # nontrivial points, along axis 1 of ndarray | ||||
|     verts = vertices[:, None, :]            # vertices, along axis 0 | ||||
|     xydiff = ntpts - verts      # Expands into (n_vertices, n_ntpts, 2) | ||||
| 
 | ||||
|     y0_le = xydiff[:, :, 1] >= 0                   # y_point >= y_vertex (axes 0, 1 for all points & vertices) | ||||
|     y1_le = numpy.roll(y0_le, -1, axis=0)          # same thing for next vertex | ||||
| 
 | ||||
|     upward = y0_le & ~y1_le         # edge passes point y coord going upwards | ||||
|     downward = ~y0_le & y1_le       # edge passes point y coord going downwards | ||||
| 
 | ||||
|     dv = numpy.roll(verts, -1, axis=0) - verts | ||||
|     is_left = (dv[..., 0] * xydiff[..., 1]        # >0 if left of dv, <0 if right, 0 if on the line | ||||
|              - dv[..., 1] * xydiff[..., 0]) | ||||
| 
 | ||||
|     winding_number = ((upward & (is_left > 0)).sum(axis=0) | ||||
|                   - (downward & (is_left < 0)).sum(axis=0)) | ||||
| 
 | ||||
|     nontrivial_inside = winding_number != 0        # filter nontrivial points based on winding number | ||||
|     if include_boundary: | ||||
|         nontrivial_inside[(is_left == 0).any(axis=0)] = True        # check if point lies on any edge | ||||
| 
 | ||||
|     inside = nontrivial.copy() | ||||
|     inside[nontrivial] = nontrivial_inside | ||||
|     return inside | ||||
| 
 | ||||
| 
 | ||||
| def union_nonzero(shapes: Sequence[ArrayLike]) -> PyPolyNode | None: | ||||
|     if not shapes: | ||||
|         return None | ||||
|     pc = Pyclipper() | ||||
|     pc.AddPaths(shapes, PT_CLIP, closed=True) | ||||
|     result = pc.Execute2(CT_UNION, PFT_NONZERO, PFT_NONZERO) | ||||
|     return result | ||||
| 
 | ||||
| 
 | ||||
| def union_evenodd(shapes: Sequence[ArrayLike]) -> list[contour_t]: | ||||
|     if not shapes: | ||||
|         return [] | ||||
|     pc = Pyclipper() | ||||
|     pc.AddPaths(shapes, PT_CLIP, closed=True) | ||||
|     return pc.Execute(CT_UNION, PFT_EVENODD, PFT_EVENODD) | ||||
| 
 | ||||
| 
 | ||||
| def intersection_evenodd( | ||||
|         subject_shapes: Sequence[ArrayLike], | ||||
|         clip_shapes: Sequence[ArrayLike], | ||||
|         clip_closed: bool = True, | ||||
|         ) -> list[contour_t]: | ||||
|     if not subject_shapes or not clip_shapes: | ||||
|         return [] | ||||
|     pc = Pyclipper() | ||||
|     pc.AddPaths(subject_shapes, PT_SUBJECT, closed=True) | ||||
|     pc.AddPaths(clip_shapes, PT_CLIP, closed=clip_closed) | ||||
|     return pc.Execute(CT_INTERSECTION, PFT_EVENODD, PFT_EVENODD) | ||||
| 
 | ||||
| 
 | ||||
| class NetsInfo: | ||||
|     nets: defaultdict[str, defaultdict[layer_t, list]] | ||||
|     net_aliases: defaultdict[str, list] | ||||
| 
 | ||||
|     def __init__(self) -> None: | ||||
|         self.nets = defaultdict(lambda: defaultdict(list)) | ||||
|         self.net_aliases = defaultdict(list) | ||||
| 
 | ||||
|     def resolve_name(self, net_name: net_name_t) -> net_name_t: | ||||
|         while net_name in self.net_aliases: | ||||
|             net_name = self.net_aliases[net_name] | ||||
|         return net_name | ||||
| 
 | ||||
|     def merge(self, net_a: net_name_t, net_b: net_name_t) -> None: | ||||
|         net_a = self.resolve_name(net_a) | ||||
|         net_b = self.resolve_name(net_b) | ||||
| 
 | ||||
|         # Always keep named nets if the other is anonymous | ||||
|         if not isinstance(net_a, str) and isinstance(net_b, str): | ||||
|             keep_net, old_net = net_b, net_a | ||||
|         else: | ||||
|             keep_net, old_net = net_a, net_b | ||||
| 
 | ||||
|         #logger.info(f'merging {old_net} into {keep_net}') | ||||
|         self.net_aliases[old_net] = keep_net | ||||
|         if old_net in self.nets: | ||||
|             for layer in self.nets[old_net]: | ||||
|                 self.nets[keep_net][layer] += self.nets[old_net][layer] | ||||
|             del self.nets[old_net] | ||||
| 
 | ||||
|     def get(self, net: net_name_t, layer: layer_t) -> list[contour_t]: | ||||
|         return self.nets[self.resolve_name(net)][layer] | ||||
| 
 | ||||
|     def get_shorted_nets(self) -> list[set[str]]: | ||||
|         shorts = defaultdict(list) | ||||
|         for kk in self.net_aliases: | ||||
|             if isinstance(kk, str): | ||||
|                 shorts[self.resolve_name(kk)].append(kk) | ||||
| 
 | ||||
|         shorted_sets = [set([kk] + others) | ||||
|                         for kk, others in shorts.items()] | ||||
|         return shorted_sets | ||||
| 
 | ||||
| 
 | ||||
| def load_polys(layers: Sequence[tuple[int, int]]) -> dict[layer_t, list[NDArray[numpy.float64]]]: | ||||
|     polys = defaultdict(list) | ||||
|     for ss in topcell.shapes: | ||||
|         if ss.layer not in layers: | ||||
|             continue | ||||
| 
 | ||||
|         if ss.repetition is None: | ||||
|             displacements = [(0, 0)] | ||||
|         else: | ||||
|             displacements = ss.repetition.displacements | ||||
| 
 | ||||
|         for displacement in displacements: | ||||
|             polys[ss.layer].append( | ||||
|                 ss.vertices + ss.offset + displacement | ||||
|                 ) | ||||
|     return dict(polys) | ||||
| 
 | ||||
| 
 | ||||
| def union_polys(polys: list[ArrayLike]) -> list[PyPolyNode]: | ||||
|     scaled_polys = scale_to_clipper(polys, CLIPPER_SCALE_FACTOR) | ||||
|     for poly in scaled_polys: | ||||
|         if (numpy.abs(poly) % 1).any(): | ||||
|             logger.warning('Warning: union_polys got non-integer coordinates; all values will be truncated.') | ||||
|             break | ||||
| 
 | ||||
|     poly_tree = union_nonzero(scaled_polys) | ||||
| 
 | ||||
|     # Partially flatten the tree, reclassifying all the "outer" (non-hole) nodes as new root nodes | ||||
|     unvisited_nodes = [poly_tree] | ||||
|     outer_nodes = [] | ||||
|     while unvisited_nodes: | ||||
|         node = unvisited_nodes.pop()    # node will be the tree parent node (a container), or a hole | ||||
|         for poly in node.Childs: | ||||
|             outer_nodes.append(poly) | ||||
|             for hole in poly.Childs: | ||||
|                 unvisited_nodes.append(hole) | ||||
| 
 | ||||
|     return outer_nodes | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| cells, props = oasis.readfile('connectivity.oas') | ||||
| #cells, props = gdsii.readfile('connectivity.gds') | ||||
| topcell = cells['top'] | ||||
| 
 | ||||
| 
 | ||||
| layer_info = { | ||||
|     ((1, 0), (1, 2), (2, 0)),   #M1 to M2 | ||||
|     ((1, 0), (1, 3), (3, 0)),   #M1 to M3 | ||||
|     ((2, 0), (2, 3), (3, 0)),   #M2 to M3 | ||||
|     } | ||||
| 
 | ||||
| metal_layers = set() | ||||
| via_layers = set() | ||||
| for top, via, bot in layer_info: | ||||
|     metal_layers.add(top) | ||||
|     metal_layers.add(bot) | ||||
|     via_layers.add(via) | ||||
| 
 | ||||
| 
 | ||||
| topcell = topcell.subset( | ||||
|     shapes_func=lambda ss: ss.layer in metal_layers | via_layers, | ||||
|     labels_func=lambda ll: ll.layer in metal_layers, | ||||
|     subpatterns_func=lambda ss: True, | ||||
|     ) | ||||
| topcell = topcell.flatten() | ||||
| 
 | ||||
| 
 | ||||
| base_metal_polys = load_polys(metal_layers) | ||||
| metal_polys = {layer: union_polys(base_metal_polys[layer]) | ||||
|                for layer in metal_layers} | ||||
| 
 | ||||
| base_via_polys = load_polys(via_layers) | ||||
| via_polys = {layer: union_polys(base_via_polys[layer]) | ||||
|              for layer in via_layers} | ||||
| 
 | ||||
| ## write out polys to gds | ||||
| #pat = Pattern('metal_polys') | ||||
| #for layer in metal_polys: | ||||
| #    for poly in metal_polys[layer]: | ||||
| #        pat.shapes.append(Polygon(layer=layer, vertices=scale_from_clipper(poly.Contour, CLIPPER_SCALE_FACTOR))) | ||||
| #        for hole in poly.Childs: | ||||
| #            pat.shapes.append(Polygon(layer=(layer[0], layer[1] + 10), vertices=scale_from_clipper(hole.Contour, CLIPPER_SCALE_FACTOR))) | ||||
| #for layer in via_polys: | ||||
| #    for poly in via_polys[layer]: | ||||
| #        pat.shapes.append(Polygon(layer=layer, vertices=scale_from_clipper(poly.Contour, CLIPPER_SCALE_FACTOR))) | ||||
| #        for hole in poly.Childs: | ||||
| #            pat.shapes.append(Polygon(layer=(layer[0], layer[1] + 10), vertices=scale_from_clipper(hole.Contour, CLIPPER_SCALE_FACTOR))) | ||||
| #gdsii.writefile(pat, '_polys.gds', 1e-9, 1e-6) | ||||
| 
 | ||||
| 
 | ||||
| net_info = NetsInfo() | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| def label_nets( | ||||
|         net_info: NetsInfo, | ||||
|         polys: Sequence[PyPolyNode], | ||||
|         point_xys: ArrayLike, | ||||
|         point_names: Sequence[str], | ||||
|         ): | ||||
|     for poly in polys: | ||||
|         poly_contour = scale_from_clipper(poly.Contour, CLIPPER_SCALE_FACTOR) | ||||
|         inside = poly_contains_points2(poly_contour, point_xys) | ||||
|         for hole in poly.Childs: | ||||
|             hole_contour = scale_from_clipper(hole.Contour, CLIPPER_SCALE_FACTOR) | ||||
|             inside &= ~poly_contains_points2(hole_contour, point_xys) | ||||
| 
 | ||||
|         inside_nets = sorted([net_name for net_name, ii in zip(point_names, inside) if ii]) | ||||
| 
 | ||||
|         if not inside.any(): | ||||
|             # No labels in this net, so it's anonymous | ||||
|             name = object() | ||||
|             net_info.nets[name][layer].append(poly) | ||||
|             continue | ||||
| 
 | ||||
|         net_info.get(inside_nets[0], layer).append(poly) | ||||
| 
 | ||||
|         if inside.sum() == 1: | ||||
|             # No short on this layer, continue | ||||
|             continue | ||||
| 
 | ||||
|         logger.warning(f'Nets {inside_nets} are shorted on layer {layer} in poly:\n {pformat(poly)}') | ||||
|         first_net, *defunct_nets = inside_nets | ||||
|         for defunct_net in defunct_nets: | ||||
|             net_info.merge(first_net, defunct_net) | ||||
| 
 | ||||
|     contours = [] | ||||
| 
 | ||||
| 
 | ||||
| def tree2oriented(polys: Sequence[PyPolyNode]) -> list[ArrayLike]: | ||||
|     contours = [] | ||||
|     for poly in polys: | ||||
|         contours.append(poly.Contour) | ||||
|         contours += [hole.Contour for hole in poly.Childs] | ||||
| 
 | ||||
|     return union_evenodd(contours) | ||||
| 
 | ||||
| 
 | ||||
| for layer in metal_layers: | ||||
|     labels = sorted([ll for ll in topcell.labels if ll.layer == layer], key=lambda ll: ll.string) | ||||
|     point_xys = [ll.offset for ll in labels] | ||||
|     point_names = [ll.string for ll in labels] | ||||
|     label_nets(net_info, metal_polys[layer], point_xys, point_names) | ||||
| 
 | ||||
| # | ||||
| #   Take EVENODD union within each net | ||||
| #   & stay in EVENODD-friendly representation | ||||
| # | ||||
| for net in net_info.nets.values(): | ||||
|     for layer in net: | ||||
|         net[layer] = tree2oriented(net[layer]) | ||||
| 
 | ||||
| for layer in via_polys: | ||||
|     via_polys[layer] = tree2oriented(via_polys[layer]) | ||||
| 
 | ||||
| ## write out nets to gds | ||||
| #pat = Pattern('nets') | ||||
| #for name, net in net_info.nets.items(): | ||||
| #    sub = Pattern(str(name)) | ||||
| #    for layer in net: | ||||
| #        print('aaaaaa', layer) | ||||
| #        for poly in net[layer]: | ||||
| #            sub.shapes.append(Polygon(layer=layer, vertices=scale_from_clipper(poly, CLIPPER_SCALE_FACTOR))) | ||||
| #    pat.addsp(sub) | ||||
| #gdsii.writefile(pat, '_nets.gds', 1e-9, 1e-6) | ||||
| 
 | ||||
| 
 | ||||
| # | ||||
| #   Merge nets based on via connectivity | ||||
| # | ||||
| merge_pairs = set() | ||||
| for top_layer, via_layer, bot_layer in layer_info: | ||||
|     vias = via_polys[via_layer] | ||||
|     if not vias: | ||||
|         continue | ||||
| 
 | ||||
|     #TODO deal with polygons that have holes (loops?) | ||||
| 
 | ||||
|     for top_name in net_info.nets.keys(): | ||||
|         top_polys = net_info.nets[top_name][top_layer] | ||||
|         if not top_polys: | ||||
|             continue | ||||
| 
 | ||||
|         for bot_name in net_info.nets.keys(): | ||||
|             if bot_name == top_name: | ||||
|                 continue | ||||
|             name_pair = tuple(sorted((top_name, bot_name), key=lambda s: id(s))) | ||||
|             if name_pair in merge_pairs: | ||||
|                 continue | ||||
| 
 | ||||
|             bot_polys = net_info.nets[bot_name][bot_layer] | ||||
|             if not bot_polys: | ||||
|                 continue | ||||
| 
 | ||||
|             via_top = intersection_evenodd(top_polys, vias) | ||||
|             overlap = intersection_evenodd(via_top, bot_polys) | ||||
| 
 | ||||
|             if not overlap: | ||||
|                 continue | ||||
| 
 | ||||
|             if isinstance(bot_name, str) and isinstance(top_name, str): | ||||
|                 logger.warning(f'Nets {top_name} and {bot_name} are shorted with via layer {via_layer} at:\n {pformat(scale_from_clipper(overlap[0], CLIPPER_SCALE_FACTOR))}') | ||||
|             merge_pairs.add(name_pair) | ||||
| 
 | ||||
| for net_a, net_b in merge_pairs: | ||||
|     net_info.merge(net_a, net_b) | ||||
| 
 | ||||
| 
 | ||||
| print('merged pairs') | ||||
| print(pformat(merge_pairs)) | ||||
| 
 | ||||
| 
 | ||||
| print('\nFinal nets:') | ||||
| print([kk for kk in net_info.nets if isinstance(kk, str)]) | ||||
| 
 | ||||
| 
 | ||||
| print('\nNet sets:') | ||||
| for short in net_info.get_shorted_nets(): | ||||
|     print('(' + ','.join(sorted(list(short))) + ')') | ||||
							
								
								
									
										38
									
								
								examples/euler_bend.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								examples/euler_bend.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| import numpy | ||||
| from numpy import pi | ||||
| 
 | ||||
| 
 | ||||
| def centerline(switchover_angle: float): | ||||
|     theta_max = numpy.sqrt(2 * switchover_angle) | ||||
| 
 | ||||
|     def gen_curve(theta_max: float): | ||||
|         xx = [] | ||||
|         yy = [] | ||||
|         for theta in numpy.linspace(0, theta_max, 100): | ||||
|             qq = numpy.linspace(0, theta, 1000) | ||||
|             xx.append(numpy.trapz( cos(qq * qq / 2), qq)) | ||||
|             yy.append(numpy.trapz(-sin(qq * qq / 2), qq)) | ||||
|         xy_part = numpy.stack((xx, yy), axis=1) | ||||
|         return xy_part | ||||
| 
 | ||||
|     AA = 1 | ||||
|     xy_part = AA * gen_curve(theta_max) | ||||
|     rmin = AA / theta_max | ||||
| 
 | ||||
|     xy = [xy_part] | ||||
|     if switchover_angle < pi / 4: | ||||
|         half_angle = pi / 4 - switchover_angle | ||||
|         qq = numpy.linspace(half_angle * 2, 0, 10) + switchover_angle | ||||
|         xc = rmin * numpy.cos(qq) | ||||
|         yc = rmin * numpy.sin(qq) + xy_part[-1, 1] | ||||
|         xc += xy_part[-1, 0] - xc[0] | ||||
|         yc += xy_part[-1, 1] - yc[0] | ||||
|         xy.append(numpy.stack((xy, yc), axis=1)) | ||||
| 
 | ||||
|     endpoint_xy = xy[-1][-1, :] | ||||
|     second_curve = xy_part[:, ::-1] + endpoint_xy - xy_part[-1, ::-1] | ||||
| 
 | ||||
|     # Remove 2x-duplicate points | ||||
|     xy = xy[(numpy.circshift(xy, 1, axis=0) != xy).any(axis=1)] | ||||
| 
 | ||||
|     return xy | ||||
| @ -31,6 +31,7 @@ from pprint import pformat | ||||
| 
 | ||||
| import numpy | ||||
| from numpy.typing import ArrayLike, NDArray | ||||
| from numpy.testing import assert_equal | ||||
| import pyarrow | ||||
| from pyarrow.cffi import ffi | ||||
| 
 | ||||
| @ -44,7 +45,7 @@ from ..library import LazyLibrary, Library, ILibrary, ILibraryView | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
| 
 | ||||
| clib = ffi.dlopen('/home/jan/projects/klamath-rs/target/debug/libklamath_rs_ext.so') | ||||
| clib = ffi.dlopen('/home/jan/projects/klamath-rs/target/release/libklamath_rs_ext.so') | ||||
| ffi.cdef('void read_path(char* path, struct ArrowArray* array, struct ArrowSchema* schema);') | ||||
| 
 | ||||
| 
 | ||||
| @ -127,10 +128,25 @@ def read_arrow( | ||||
|     """ | ||||
|     library_info = _read_header(libarr) | ||||
| 
 | ||||
|     layer_names_np = libarr['layers'].values.to_numpy().view('i2').reshape((-1, 2)) | ||||
|     layer_tups = [tuple(pair) for pair in layer_names_np] | ||||
|     bnd = libarr['cells'].values.field('boundaries') | ||||
|     layer_inds = bnd.values.field('layer').to_numpy() | ||||
|     boundary = dict( | ||||
|         offsets = bnd.offsets.to_numpy(), | ||||
|         xy_arr = bnd.values.field('xy').values.to_numpy().reshape((-1, 2)), | ||||
|         xy_off = bnd.values.field('xy').offsets.to_numpy() // 2, | ||||
|         layer_tups = layer_tups, | ||||
|         layer_inds = layer_inds, | ||||
|         prop_off = bnd.values.field('properties').offsets.to_numpy(), | ||||
|         prop_key = bnd.values.field('properties').values.field('key').to_numpy(), | ||||
|         prop_val = bnd.values.field('properties').values.field('value').to_pylist(), | ||||
|         ) | ||||
| 
 | ||||
|     mlib = Library() | ||||
|     for cell in libarr['cells']: | ||||
|     for cc, cell in enumerate(libarr['cells']): | ||||
|         name = libarr['cell_names'][cell['id'].as_py()].as_py() | ||||
|         pat = read_cell(cell, libarr['cell_names'], raw_mode=raw_mode) | ||||
|         pat = read_cell(cc, cell, libarr['cell_names'], raw_mode=raw_mode, boundary=boundary) | ||||
|         mlib[name] = pat | ||||
| 
 | ||||
|     return mlib, library_info | ||||
| @ -149,8 +165,10 @@ def _read_header(libarr: pyarrow.Array) -> dict[str, Any]: | ||||
| 
 | ||||
| 
 | ||||
| def read_cell( | ||||
|         cc: int, | ||||
|         cellarr: pyarrow.Array, | ||||
|         cell_names: pyarrow.Array, | ||||
|         boundary: dict[str, NDArray], | ||||
|         raw_mode: bool = True, | ||||
|         ) -> Pattern: | ||||
|     """ | ||||
| @ -190,22 +208,32 @@ def read_cell( | ||||
|         ref = Ref(**args) | ||||
|         pat.refs[target].append(ref) | ||||
| 
 | ||||
|     for bnd in cellarr['boundaries']: | ||||
|         layer = (bnd['layer'].as_py(), bnd['dtype'].as_py()) | ||||
|         args = dict( | ||||
|             vertices = bnd['xy'].values.to_numpy().reshape((-1, 2))[:-1], | ||||
|             raw = raw_mode, | ||||
|             offset = numpy.zeros(2), | ||||
|             ) | ||||
|     bnd_off = boundary['offsets'] | ||||
|     bnd_xy_val = boundary['xy_arr'] | ||||
|     bnd_xy_off = boundary['xy_off'] | ||||
|     layer_tups = boundary['layer_tups'] | ||||
|     layer_inds = boundary['layer_inds'] | ||||
|     prop_off = boundary['prop_off'] | ||||
|     prop_key = boundary['prop_key'] | ||||
|     prop_val = boundary['prop_val'] | ||||
|     slc = slice(bnd_off[cc], bnd_off[cc + 1] + 1) | ||||
|     bnd_offs = bnd_xy_off[slc] | ||||
|     prop_offs = prop_off[slc] | ||||
|     zeros = numpy.zeros((len(bnd_offs) - 1, 2)) | ||||
|     for bb in range(len(bnd_offs) - 1): | ||||
|         layer = layer_tups[layer_inds[bb]] | ||||
|         vertices = bnd_xy_val[bnd_offs[bb]:bnd_offs[bb + 1] - 1]    # -1 to drop closing point | ||||
| 
 | ||||
|         if (props := bnd['properties']).is_valid: | ||||
|             args['annotations'] = _properties_to_annotations(props) | ||||
|         prop_ii, prop_ff = prop_offs[bb], prop_offs[bb + 1] | ||||
|         if prop_ii < prop_ff: | ||||
|             ann = {prop_key[off]: prop_val[off] for off in range(prop_ii, prop_ff)} | ||||
|             args = dict(annotations = ann) | ||||
| 
 | ||||
|         poly = Polygon(**args) | ||||
|         poly = Polygon(vertices=vertices, offset=zeros[bb], raw=raw_mode) | ||||
|         pat.shapes[layer].append(poly) | ||||
| 
 | ||||
|     for gpath in cellarr['paths']: | ||||
|         layer = (gpath['layer'].as_py(), gpath['dtype'].as_py()) | ||||
|         layer = (gpath['layer'].as_py(),) | ||||
|         args = dict( | ||||
|             vertices = gpath['xy'].values.to_numpy().reshape((-1, 2)), | ||||
|             offset = numpy.zeros(2), | ||||
| @ -236,7 +264,7 @@ def read_cell( | ||||
|         pat.shapes[layer].append(mpath) | ||||
| 
 | ||||
|     for gtext in cellarr['texts']: | ||||
|         layer = (gtext['layer'].as_py(), gtext['dtype'].as_py()) | ||||
|         layer = (gtext['layer'].as_py(),) | ||||
|         args = dict( | ||||
|             offset = (gtext['x'].as_py(), gtext['y'].as_py()), | ||||
|             string = gtext['string'].as_py(), | ||||
|  | ||||
							
								
								
									
										3
									
								
								masque/test/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								masque/test/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| """ | ||||
| Tests (run with `python3 -m pytest -rxPXs | tee results.txt`) | ||||
| """ | ||||
							
								
								
									
										31
									
								
								masque/test/conftest.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								masque/test/conftest.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| """ | ||||
| 
 | ||||
| Test fixtures | ||||
| 
 | ||||
| """ | ||||
| # ruff: noqa: ARG001 | ||||
| from typing import Any | ||||
| import numpy | ||||
| from numpy.typing import NDArray | ||||
| 
 | ||||
| import pytest       # type: ignore | ||||
| 
 | ||||
| 
 | ||||
| FixtureRequest = Any | ||||
| PRNG = numpy.random.RandomState(12345) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.fixture(scope='module', | ||||
|                 params=[(5, 5, 1), | ||||
|                         (5, 1, 5), | ||||
|                         (5, 5, 5), | ||||
|                         # (7, 7, 7), | ||||
|                        ]) | ||||
| def shape(request: FixtureRequest) -> tuple[int, ...]: | ||||
|     return (3, *request.param) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.fixture(scope='module', params=[1.0, 1.5]) | ||||
| def epsilon_bg(request: FixtureRequest) -> float: | ||||
|     return request.param | ||||
| 
 | ||||
							
								
								
									
										35
									
								
								masque/test/test_fdfd.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								masque/test/test_fdfd.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| # ruff: noqa: ARG001 | ||||
| import dataclasses | ||||
| import pytest       # type: ignore | ||||
| import numpy | ||||
| from numpy import pi | ||||
| from numpy.typing import NDArray | ||||
| #from numpy.testing import assert_allclose, assert_array_equal | ||||
| 
 | ||||
| from .. import Pattern, Arc | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| def test_Arc_arclen() -> None: | ||||
|     max_arclen = 1000 | ||||
| 
 | ||||
|     wedge = Arc(radii=( 50,  50), angles=(-pi/4, pi/4), width=100) | ||||
|     arc   = Arc(radii=(100, 100), angles=(-pi/4, pi/4), width=1) | ||||
| 
 | ||||
|     verts_wedge = wedge.to_polygons(max_arclen=max_arclen)[0].vertices | ||||
|     verts_arc = arc.to_polygons(max_arclen=max_arclen)[0].vertices | ||||
| 
 | ||||
|     dxy_wedge = numpy.roll(verts_wedge, 1, axis=0) - verts_wedge | ||||
|     dxy_arc   = numpy.roll(verts_arc, 1, axis=0) - verts_arc | ||||
| 
 | ||||
|     dl_wedge = numpy.sqrt((dxy_wedge * dxy_wedge).sum(axis=1)) | ||||
|     dl_arc = numpy.sqrt((dxy_arc * dxy_arc).sum(axis=1)) | ||||
| 
 | ||||
|     assert dl_wedge.max() < max_arclen | ||||
|     assert dl_arc.max() < max_arclen | ||||
| 
 | ||||
|     print(verts_wedge.shape[0]) | ||||
|     print(verts_arc.shape[0]) | ||||
|     print(dl_wedge, dl_arc) | ||||
|     Pattern(shapes={(0, 0): [wedge, arc]}).visualize() | ||||
|     assert False | ||||
| @ -46,6 +46,21 @@ def bezier( | ||||
|     return qq | ||||
| 
 | ||||
| 
 | ||||
| def bezier2( | ||||
|         nodes: ArrayLike, | ||||
|         tt: ArrayLike, | ||||
|         ) -> NDArray[numpy.float64]: | ||||
|     nodes = numpy.asarray(nodes) | ||||
|     tt = numpy.asarray(tt)[:, None, None] | ||||
|     nn = nodes.shape[0] | ||||
|     qq = nodes[None, :, :] * numpy.ones(tt.size)[:, None, None] | ||||
|     for kk in range(1, nn): | ||||
|         gg = nn - kk | ||||
|         qq[:, :gg, :] = (1 - tt) * qq[:, :gg, :] + tt * qq[:, 1:gg + 1, :] | ||||
|         #for ii in range(nn - kk): | ||||
|         #    qq[:, ii] = (1 - tt[:, None]) * qq[:, ii] + tt[:, None] * qq[:, ii + 1] | ||||
|     return qq[:, 0, :] | ||||
| 
 | ||||
| 
 | ||||
| def euler_bend( | ||||
|         switchover_angle: float, | ||||
|  | ||||
							
								
								
									
										5
									
								
								perftest.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								perftest.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| import time | ||||
| from masque.file.gdsii_arrow import readfile | ||||
| 
 | ||||
| #time.sleep(5) | ||||
| lib, props = readfile('/home/jan/Downloads/sg13g2_io.gds') | ||||
							
								
								
									
										1
									
								
								test_slow.ssc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test_slow.ssc
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user