Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/release/changelogs/next.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#### Improvements 🧹

- performance: reduce repeated work in Dagre ranking, text measurement, SVG preparation, and PNG encoding
- performance: reduce repeated work in selective imports, dynamic grid layout, and PNG connection rendering
- exports: reduce PNG memory usage and support images above the previous 67-megapixel limit
- performance: SVG rendering is approximately 10× faster across the E2E corpus. Real-world diagrams compile, lay out, and render approximately 3× faster at the median.
Expand Down
4 changes: 4 additions & 0 deletions d2cli/raster_png_encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,10 @@ func rasterPNGUpFilter(destination, raw, prior []byte) int {
_ = prior[len(raw)-1]
destination[0] = 2
destination = destination[1:]
if bytes.Equal(raw, prior) {
clear(destination[:len(raw)])
return 0
}
cost := 0
for index, value := range raw {
destination[index] = value - prior[index]
Expand Down
160 changes: 160 additions & 0 deletions d2cli/raster_png_filter_runs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package d2cli

import (
"bytes"
"math"
"math/rand"
"testing"
)

// Compare the actual scores and scratch writes against the pre-optimization
// scalar filters, including early termination and runs crossing pixel boundaries.
func TestRasterPNGFilterRunsMatchScalar(t *testing.T) {
random := rand.New(rand.NewSource(2879))
for _, channels := range []int{3, 4} {
for _, width := range []int{1, 2, 5, 6, 7, 8, 10, 15, 16, 17, 31, 32, 33, 63, 64, 65, 257} {
for pattern := 0; pattern < 9; pattern++ {
raw, prior := make([]byte, width*channels), make([]byte, width*channels)
random.Read(raw)
random.Read(prior)
switch pattern {
case 1:
copy(raw, prior)
case 2, 3:
for i := range raw {
raw[i] = byte(i%channels*53 + 1)
prior[i] = raw[i]
if pattern == 3 {
prior[i] += 19
}
}
case 4:
copy(raw, prior)
for i := channels - 1; i < len(raw); i += 16 {
raw[i] ^= 0x81
}
case 5:
for i := range raw {
raw[i] = 255
prior[i] = 255
if i%32 == 15 {
raw[i] = byte(i)
}
}
case 6:
for i := 0; i < min(64, len(raw)); i++ {
raw[i] = 255
prior[i] = 255
}
case 7:
for i := 16; i+16 <= len(raw); i += 32 {
copy(raw[i:i+16], prior[i:i+16])
}
case 8:
clear(raw)
clear(prior)
}
thresholds := []int{0, 1, 2, 7, 255, 65535, math.MaxInt}
scratch := make([]byte, len(raw)+1)
for _, fullCost := range []int{
referenceRasterPNGUpFilter(scratch, raw, prior),
referenceRasterPNGSubFilter(scratch, raw, math.MaxInt, channels),
referenceRasterPNGPaethFilter(scratch, raw, prior, math.MaxInt, channels),
} {
thresholds = append(thresholds, max(0, fullCost-1), fullCost, fullCost+1)
}
for _, stopAt := range thresholds {
for filter := 0; filter < 3; filter++ {
got, want := bytes.Repeat([]byte{0xa5}, len(raw)+1), bytes.Repeat([]byte{0xa5}, len(raw)+1)
var gotCost, wantCost int
switch filter {
case 0:
gotCost = rasterPNGUpFilter(got, raw, prior)
wantCost = referenceRasterPNGUpFilter(want, raw, prior)
case 1:
gotCost = rasterPNGSubFilter(got, raw, stopAt, channels)
wantCost = referenceRasterPNGSubFilter(want, raw, stopAt, channels)
case 2:
gotCost = rasterPNGPaethFilter(got, raw, prior, stopAt, channels)
wantCost = referenceRasterPNGPaethFilter(want, raw, prior, stopAt, channels)
}
if gotCost != wantCost || !bytes.Equal(got, want) {
t.Fatalf("channels=%d width=%d pattern=%d stop=%d filter=%d: cost %d != %d or scratch differs", channels, width, pattern, stopAt, filter, gotCost, wantCost)
}
}
}
}
}
}
}

// Frozen scalar implementations from 70affc0e.
func referenceRasterPNGUpFilter(destination, raw, prior []byte) int {
_ = prior[len(raw)-1]
destination[0] = 2
destination = destination[1:]
cost := 0
for index, value := range raw {
destination[index] = value - prior[index]
cost += rasterPNGAbs8(destination[index])
}
return cost
}

func referenceRasterPNGSubFilter(destination, raw []byte, stopAt, channels int) int {
destination[0] = 1
destination = destination[1:]
cost := 0
for index := 0; index < channels; index++ {
destination[index] = raw[index]
cost += rasterPNGAbs8(destination[index])
if cost >= stopAt {
return cost
}
}
for index := channels; index < len(raw); index++ {
destination[index] = raw[index] - raw[index-channels]
cost += rasterPNGAbs8(destination[index])
if cost >= stopAt {
break
}
}
return cost
}

func referenceRasterPNGPaethFilter(destination, raw, prior []byte, stopAt, channels int) int {
_ = prior[len(raw)-1]
destination[0] = 4
destination = destination[1:]
cost := 0
for index := 0; index < channels; index++ {
destination[index] = raw[index] - prior[index]
cost += rasterPNGAbs8(destination[index])
if cost >= stopAt {
return cost
}
}
for index := channels; index < len(raw); index++ {
left := raw[index-channels]
upperLeft := prior[index-channels]
upper := prior[index]
leftDistance := rasterPNGByteDistance(upper, upperLeft)
upperDistance := rasterPNGByteDistance(left, upperLeft)
diagonalDistance := int(left) + int(upper) - 2*int(upperLeft)
if diagonalDistance < 0 {
diagonalDistance = -diagonalDistance
}
predictor := upperLeft
if leftDistance <= upperDistance && leftDistance <= diagonalDistance {
predictor = left
} else if upperDistance <= diagonalDistance {
predictor = upper
}
destination[index] = raw[index] - predictor
cost += rasterPNGAbs8(destination[index])
if cost >= stopAt {
break
}
}
return cost
}
104 changes: 104 additions & 0 deletions d2cli/raster_png_mixed_content_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package d2cli

import (
"bytes"
"context"
"fmt"
"image"
"image/png"
"math/rand"
"testing"
)

// These fixtures exercise unchanged prefixes followed by varied content.
// Fixture generation is outside timed runs.
func rasterPNGMixedContentImages() []struct {
name string
img *image.NRGBA
} {
var cases []struct {
name string
img *image.NRGBA
}
for _, kind := range []string{"noise", "gradient"} {
for _, margin := range []int{8, 64} {
img := image.NewNRGBA(image.Rect(0, 0, 512, 512))
random := rand.New(rand.NewSource(0xD2))
for y := 0; y < 512; y++ {
for x := 0; x < 512; x++ {
offset := img.PixOffset(x, y)
// Consume one value for every pixel so both margin widths
// have the same underlying noise at matching coordinates.
value := random.Uint32()
red, green, blue := byte(value), byte(value>>8), byte(value>>16)
if kind == "gradient" {
// Match the existing encoder benchmark's diagonal
// gradient: colors vary both within and between rows.
red, green, blue = byte(x), byte(y), byte(x+y)
}
if x < margin {
red, green, blue = 0xff, 0xff, 0xff
}
img.Pix[offset], img.Pix[offset+1], img.Pix[offset+2], img.Pix[offset+3] = red, green, blue, 0xff
}
}
cases = append(cases, struct {
name string
img *image.NRGBA
}{name: fmt.Sprintf("%s/margin-%d", kind, margin), img: img})
}
}
return cases
}

var benchmarkRasterPNGMixedBytes []byte

// BenchmarkRasterPNGMixedContent uses the native subbenchmark lifecycle from
// BenchmarkRasterPNGEncoder: one encoder per subbenchmark, retained across
// iterations and closed afterward. Each encode allocates its output normally.
func BenchmarkRasterPNGMixedContent(b *testing.B) {
for _, benchmark := range rasterPNGMixedContentImages() {
b.Run(benchmark.name+"/native", func(b *testing.B) {
var encoder rasterPNGEncoder
defer encoder.close()
b.ReportAllocs()
for range b.N {
encoded, err := encoder.encode(context.Background(), benchmark.img)
if err != nil {
b.Fatal(err)
}
benchmarkRasterPNGMixedBytes = encoded
}
})
}
}

func TestRasterPNGMixedContentMatchesStdlib(t *testing.T) {
var encoder rasterPNGEncoder
defer encoder.close()
for _, test := range rasterPNGMixedContentImages() {
t.Run(test.name, func(t *testing.T) {
before := bytes.Clone(test.img.Pix)
var expected bytes.Buffer
stdlib := png.Encoder{CompressionLevel: png.BestSpeed}
if err := stdlib.Encode(&expected, test.img); err != nil {
t.Fatal(err)
}
// Both inputs are opaque NRGBA, so native encoding must emit
// the same truecolor PNG bytes and filter choices as image/png.
// Repeat to check retained encoder state as well as first use.
for pass := 0; pass < 2; pass++ {
got, err := encoder.encode(context.Background(), test.img)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(got, expected.Bytes()) {
t.Fatalf("pass %d: native PNG differs from image/png BestSpeed", pass)
}
if !bytes.Equal(test.img.Pix, before) {
t.Fatalf("pass %d: encoding mutated source pixels", pass)
}
}
})
}
}
21 changes: 21 additions & 0 deletions d2layouts/d2dagrelayout/real_world_benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package d2dagrelayout

import (
"os"
"path/filepath"
"testing"
)

// Keep layout measurements separate from parsing and font measurement, using
// the same real-world sources as the D2 end-to-end output compatibility suite.
func BenchmarkDagreRealWorld(b *testing.B) {
for _, name := range []string{"tpmjs_architecture", "spyre_encoder", "mocha_soc", "fulcro_rad", "queue_workers"} {
b.Run(name, func(b *testing.B) {
source, err := os.ReadFile(filepath.Join("..", "..", "e2etests", "testdata", "files", name+".d2"))
if err != nil {
b.Fatal(err)
}
benchmarkDagreLayout(b, string(source))
})
}
}
Loading
Loading