github.com/janelia-flyem/dvid@v1.0.0/datatype/common/labels/compressed_test.go (about) 1 package labels 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "encoding/binary" 7 "fmt" 8 "io/ioutil" 9 "math/rand" 10 "os" 11 "path/filepath" 12 "runtime" 13 "testing" 14 15 "github.com/janelia-flyem/dvid/dvid" 16 lz4 "github.com/janelia-flyem/go/golz4-updated" 17 ) 18 19 type testData struct { 20 u []uint64 21 b []byte 22 filename string 23 } 24 25 func (d testData) String() string { 26 return filepath.Base(d.filename) 27 } 28 29 func solidTestData(label uint64) (td testData) { 30 numVoxels := 64 * 64 * 64 31 td.u = make([]uint64, numVoxels) 32 td.b = dvid.AliasUint64ToByte(td.u) 33 td.filename = fmt.Sprintf("solid volume of label %d", label) 34 for i := 0; i < numVoxels; i++ { 35 td.u[i] = label 36 } 37 return 38 } 39 40 var testFiles = []string{ 41 "../../../test_data/fib19-64x64x64-sample1.dat.gz", 42 "../../../test_data/fib19-64x64x64-sample2.dat.gz", 43 "../../../test_data/cx-64x64x64-sample1.dat.gz", 44 "../../../test_data/cx-64x64x64-sample2.dat.gz", 45 } 46 47 func loadData(filename string) (td testData, err error) { 48 td.b, err = readGzipFile(filename) 49 if err != nil { 50 return 51 } 52 td.u, err = dvid.AliasByteToUint64(td.b) 53 if err != nil { 54 return 55 } 56 td.filename = filename 57 return 58 } 59 60 func loadTestData(t *testing.T, filename string) (td testData) { 61 var err error 62 td.b, err = readGzipFile(filename) 63 if err != nil { 64 t.Fatalf("unable to open test data file %q: %v\n", filename, err) 65 } 66 td.u, err = dvid.AliasByteToUint64(td.b) 67 if err != nil { 68 t.Fatalf("unable to create alias []uint64 for data file %q: %v\n", filename, err) 69 } 70 td.filename = filename 71 return 72 } 73 74 func readGzipFile(filename string) ([]byte, error) { 75 f, err := os.Open(filename) 76 if err != nil { 77 return nil, err 78 } 79 defer f.Close() 80 81 fz, err := gzip.NewReader(f) 82 if err != nil { 83 return nil, err 84 } 85 defer fz.Close() 86 87 data, err := ioutil.ReadAll(fz) 88 if err != nil { 89 return nil, err 90 } 91 return data, nil 92 } 93 94 func checkBytes(t *testing.T, text string, expected, got []byte) { 95 if len(expected) != len(got) { 96 t.Errorf("%s byte mismatch: expected %d bytes, got %d bytes\n", text, len(expected), len(got)) 97 } 98 for i, val := range got { 99 if expected[i] != val { 100 t.Errorf("%s byte mismatch found at index %d, expected %d, got %d\n", text, i, expected[i], val) 101 return 102 } 103 } 104 } 105 106 func checkLabels(t *testing.T, text string, expected, got []byte) { 107 if len(expected) != len(got) { 108 t.Errorf("%s byte mismatch: expected %d bytes, got %d bytes\n", text, len(expected), len(got)) 109 } 110 expectLabels, err := dvid.AliasByteToUint64(expected) 111 if err != nil { 112 t.Fatal(err) 113 } 114 gotLabels, err := dvid.AliasByteToUint64(got) 115 if err != nil { 116 t.Fatal(err) 117 } 118 errmsg := 0 119 for i, val := range gotLabels { 120 if expectLabels[i] != val { 121 _, fn, line, _ := runtime.Caller(1) 122 t.Errorf("%s label mismatch found at index %d, expected %d, got %d [%s:%d]\n", text, i, expectLabels[i], val, fn, line) 123 errmsg++ 124 if errmsg > 5 { 125 return 126 } 127 } else if errmsg > 0 { 128 t.Errorf("yet no mismatch at index %d, expected %d, got %d\n", i, expectLabels[i], val) 129 } 130 } 131 runtime.KeepAlive(&expected) 132 runtime.KeepAlive(&got) 133 } 134 135 func printRatio(t *testing.T, curDesc string, cur, orig int, compareDesc string, compare int) { 136 p1 := 100.0 * float32(cur) / float32(orig) 137 p2 := float32(cur) / float32(compare) 138 t.Logf("%s compression result: %d (%4.2f%% orig, %4.2f x %s)\n", curDesc, cur, p1, p2, compareDesc) 139 } 140 141 func blockTest(t *testing.T, d testData) { 142 var err error 143 var origLZ4Size int 144 origLZ4 := make([]byte, lz4.CompressBound(d.b)) 145 if origLZ4Size, err = lz4.Compress(d.b, origLZ4); err != nil { 146 t.Fatal(err) 147 } 148 printRatio(t, "Orig LZ4", origLZ4Size, len(d.b), "Orig", len(d.b)) 149 150 labels := make(map[uint64]int) 151 for _, label := range d.u { 152 labels[label]++ 153 } 154 for label, voxels := range labels { 155 t.Logf("Label %12d: %8d voxels\n", label, voxels) 156 } 157 158 cseg, err := oldCompressUint64(d.u, dvid.Point3d{64, 64, 64}) 159 if err != nil { 160 t.Fatal(err) 161 } 162 csegBytes := dvid.AliasUint32ToByte(cseg) 163 block, err := MakeBlock(d.b, dvid.Point3d{64, 64, 64}) 164 if err != nil { 165 t.Fatal(err) 166 } 167 dvidBytes, _ := block.MarshalBinary() 168 169 printRatio(t, "Goog", len(csegBytes), len(d.b), "DVID", len(dvidBytes)) 170 printRatio(t, "DVID", len(dvidBytes), len(d.b), "Goog", len(csegBytes)) 171 172 var gzipOut bytes.Buffer 173 zw := gzip.NewWriter(&gzipOut) 174 if _, err = zw.Write(csegBytes); err != nil { 175 t.Fatal(err) 176 } 177 zw.Flush() 178 runtime.KeepAlive(&cseg) 179 csegGzip := make([]byte, gzipOut.Len()) 180 copy(csegGzip, gzipOut.Bytes()) 181 gzipOut.Reset() 182 if _, err = zw.Write(dvidBytes); err != nil { 183 t.Fatal(err) 184 } 185 zw.Flush() 186 dvidGzip := make([]byte, gzipOut.Len()) 187 copy(dvidGzip, gzipOut.Bytes()) 188 189 printRatio(t, "Goog GZIP", len(csegGzip), len(d.b), "DVID GZIP", len(dvidGzip)) 190 printRatio(t, "DVID GZIP", len(dvidGzip), len(d.b), "Goog GZIP", len(csegGzip)) 191 192 var csegLZ4Size, dvidLZ4Size int 193 csegLZ4 := make([]byte, lz4.CompressBound(csegBytes)) 194 if csegLZ4Size, err = lz4.Compress(csegBytes, csegLZ4); err != nil { 195 t.Fatal(err) 196 } 197 dvidLZ4 := make([]byte, lz4.CompressBound(dvidBytes)) 198 if dvidLZ4Size, err = lz4.Compress(dvidBytes, dvidLZ4); err != nil { 199 t.Fatal(err) 200 } 201 202 printRatio(t, "Goog LZ4 ", csegLZ4Size, len(d.b), "DVID LZ4 ", dvidLZ4Size) 203 printRatio(t, "DVID LZ4 ", dvidLZ4Size, len(d.b), "Goog LZ4 ", csegLZ4Size) 204 205 // test DVID block output result 206 redata, size := block.MakeLabelVolume() 207 208 if size[0] != 64 || size[1] != 64 || size[2] != 64 { 209 t.Errorf("expected DVID compression size to be 64x64x64, got %s\n", size) 210 } 211 checkLabels(t, "DVID compression", d.b, redata) 212 213 // make sure the blocks properly Marshal and Unmarshal 214 serialization, _ := block.MarshalBinary() 215 datacopy := make([]byte, len(serialization)) 216 copy(datacopy, serialization) 217 var block2 Block 218 if err := block2.UnmarshalBinary(datacopy); err != nil { 219 t.Fatal(err) 220 } 221 redata2, size2 := block2.MakeLabelVolume() 222 if size2[0] != 64 || size2[1] != 64 || size2[2] != 64 { 223 t.Errorf("expected DVID compression size to be 64x64x64, got %s\n", size2) 224 } 225 checkLabels(t, "marshal/unmarshal copy", redata, redata2) 226 } 227 228 func TestBlockCompression(t *testing.T) { 229 solid2serialization := make([]byte, 24) 230 binary.LittleEndian.PutUint32(solid2serialization[0:4], 8) 231 binary.LittleEndian.PutUint32(solid2serialization[4:8], 8) 232 binary.LittleEndian.PutUint32(solid2serialization[8:12], 8) 233 binary.LittleEndian.PutUint32(solid2serialization[12:16], 1) 234 binary.LittleEndian.PutUint64(solid2serialization[16:24], 2) 235 var block Block 236 if err := block.UnmarshalBinary(solid2serialization); err != nil { 237 t.Fatal(err) 238 } 239 if block.Value(dvid.Point3d{34, 22, 12}) != 2 { 240 t.Errorf("Expected 2, got %d\n", block.Value(dvid.Point3d{34, 22, 12})) 241 } 242 if block.Value(dvid.Point3d{58, 4, 31}) != 2 { 243 t.Errorf("Expected 2, got %d\n", block.Value(dvid.Point3d{58, 4, 31})) 244 } 245 246 solid2, size := block.MakeLabelVolume() 247 if !size.Equals(dvid.Point3d{64, 64, 64}) { 248 t.Errorf("Expected solid2 block size of %s, got %s\n", "(64,64,64)", size) 249 } 250 if len(solid2) != 64*64*64*8 { 251 t.Errorf("Expected solid2 uint64 array to have 64x64x64x8 bytes, got %d bytes instead", len(solid2)) 252 } 253 uint64array, err := dvid.AliasByteToUint64(solid2) 254 if err != nil { 255 t.Fatal(err) 256 } 257 for i := 0; i < 64*64*64; i++ { 258 if uint64array[i] != 2 { 259 t.Fatalf("Expected solid2 label volume to have all 2's, found %d at pos %d\n", uint64array[i], i) 260 } 261 } 262 runtime.KeepAlive(&solid2) 263 264 blockTest(t, solidTestData(0)) 265 blockTest(t, solidTestData(2)) 266 for _, filename := range testFiles { 267 blockTest(t, loadTestData(t, filename)) 268 } 269 270 numVoxels := 64 * 64 * 64 271 testvol := make([]uint64, numVoxels) 272 for i := 0; i < numVoxels; i++ { 273 testvol[i] = uint64(i) 274 } 275 276 bptr, err := MakeBlock(dvid.AliasUint64ToByte(testvol), dvid.Point3d{64, 64, 64}) 277 if err != nil { 278 t.Fatalf("error making block: %v\n", err) 279 } 280 runtime.KeepAlive(&testvol) 281 testvol2, size := bptr.MakeLabelVolume() 282 if size[0] != 64 || size[1] != 64 || size[2] != 64 { 283 t.Fatalf("error in size after making block: %v\n", size) 284 } 285 checkLabels(t, "block compress/uncompress", dvid.AliasUint64ToByte(testvol), testvol2) 286 runtime.KeepAlive(&testvol) 287 i := uint64(12*64*64 + 22*64 + 34) 288 if bptr.Value(dvid.Point3d{34, 22, 12}) != i { 289 t.Errorf("Expected %d, got %d\n", bptr.Value(dvid.Point3d{34, 22, 12}), i) 290 } 291 i = 31*64*64 + 4*64 + 58 292 if bptr.Value(dvid.Point3d{58, 4, 31}) != i { 293 t.Errorf("Expected %d, got %d\n", bptr.Value(dvid.Point3d{58, 4, 31}), i) 294 } 295 } 296 297 func TestBlockDownres(t *testing.T) { 298 // Test solid blocks 299 solidOctants := [8]*Block{ 300 MakeSolidBlock(3, dvid.Point3d{64, 64, 64}), 301 MakeSolidBlock(3, dvid.Point3d{64, 64, 64}), 302 MakeSolidBlock(9, dvid.Point3d{64, 64, 64}), 303 nil, 304 MakeSolidBlock(12, dvid.Point3d{64, 64, 64}), 305 MakeSolidBlock(21, dvid.Point3d{64, 64, 64}), 306 MakeSolidBlock(83, dvid.Point3d{64, 64, 64}), 307 MakeSolidBlock(129, dvid.Point3d{64, 64, 64}), 308 } 309 310 // make reference volume that is downres. 311 gt := make([]uint64, 64*64*64) 312 for z := 0; z < 32; z++ { 313 for y := 0; y < 32; y++ { 314 for x := 0; x < 32; x++ { 315 // octant (0,0,0) 316 i := z*64*64 + y*64 + x 317 gt[i] = 3 318 319 // octant (1,0,0) 320 i = z*64*64 + y*64 + x + 32 321 gt[i] = 3 322 323 // octant (0,1,0) 324 i = z*64*64 + (y+32)*64 + x 325 gt[i] = 9 326 327 // octant (1,1,0) 328 i = z*64*64 + (y+32)*64 + x + 32 329 gt[i] = 0 330 331 // octant (0,0,1) 332 i = (z+32)*64*64 + y*64 + x 333 gt[i] = 12 334 335 // octant (1,0,1) 336 i = (z+32)*64*64 + y*64 + x + 32 337 gt[i] = 21 338 339 // octant (0,1,1) 340 i = (z+32)*64*64 + (y+32)*64 + x 341 gt[i] = 83 342 343 // octant (1,1,1) 344 i = (z+32)*64*64 + (y+32)*64 + x + 32 345 gt[i] = 129 346 } 347 } 348 } 349 gtarr := dvid.AliasUint64ToByte(gt) 350 351 // run tests using solid block octants 352 var b Block 353 b.Size = dvid.Point3d{64, 64, 64} 354 if err := b.DownresSlow(solidOctants); err != nil { 355 t.Fatalf("bad downres: %v\n", err) 356 } 357 resultBytes, size := b.MakeLabelVolume() 358 if !size.Equals(b.Size) { 359 t.Fatalf("expected downres block size to be %s, got %s\n", b.Size, size) 360 } 361 if len(resultBytes) != 64*64*64*8 { 362 t.Fatalf("expected downres block volume bytes to be 64^3 * 8, not %d\n", len(resultBytes)) 363 } 364 checkLabels(t, "checking DownresSlow with ground truth", gtarr, resultBytes) 365 366 var b2 Block 367 b2.Size = dvid.Point3d{64, 64, 64} 368 if err := b2.Downres(solidOctants); err != nil { 369 t.Fatalf("bad downres: %v\n", err) 370 } 371 resultBytes, size = b2.MakeLabelVolume() 372 if !size.Equals(b.Size) { 373 t.Fatalf("expected downres block size to be %s, got %s\n", b2.Size, size) 374 } 375 if len(resultBytes) != 64*64*64*8 { 376 t.Fatalf("expected downres block volume bytes to be 64^3 * 8, not %d\n", len(resultBytes)) 377 } 378 checkLabels(t, "checking Downres with ground truth", gtarr, resultBytes) 379 runtime.KeepAlive(>) 380 } 381 382 func setLabel(vol []uint64, size, x, y, z int, label uint64) { 383 i := z*size*size + y*size + x 384 vol[i] = label 385 } 386 387 func TestSolidBlockRLE(t *testing.T) { 388 var buf bytes.Buffer 389 lbls := Set{} 390 lbls[3] = struct{}{} 391 outOp := NewOutputOp(&buf) 392 go WriteRLEs(lbls, outOp, dvid.Bounds{}) 393 394 block := MakeSolidBlock(3, dvid.Point3d{64, 64, 64}) 395 pb := PositionedBlock{ 396 Block: *block, 397 BCoord: dvid.ChunkPoint3d{2, 1, 2}.ToIZYXString(), 398 } 399 outOp.Process(&pb) 400 401 pb2 := PositionedBlock{ 402 Block: *block, 403 BCoord: dvid.ChunkPoint3d{3, 1, 2}.ToIZYXString(), 404 } 405 outOp.Process(&pb2) 406 407 // include a solid half-block so we can make sure RLE pasting across blocks works. 408 numVoxels := 64 * 64 * 64 409 testvol := make([]uint64, numVoxels) 410 for z := 0; z < 64; z++ { 411 for y := 0; y < 32; y++ { 412 for x := 0; x < 64; x++ { 413 i := z*64*64 + y*64 + x 414 testvol[i] = 3 415 } 416 } 417 } 418 block2, err := MakeBlock(dvid.AliasUint64ToByte(testvol), dvid.Point3d{64, 64, 64}) 419 if err != nil { 420 t.Fatalf("error making block: %v\n", err) 421 } 422 runtime.KeepAlive(&testvol) 423 pts := []dvid.Point3d{dvid.Point3d{10, 10, 10}, dvid.Point3d{40, 40, 40}, dvid.Point3d{58, 58, 58}} 424 labels := block2.GetPointLabels(pts) 425 if len(labels) != 3 { 426 t.Fatalf("expected 3 labels back, got %d\n", len(labels)) 427 } 428 if labels[0] != 3 { 429 t.Errorf("Expected pt %s is label 3, got %d\n", pts[0], labels[0]) 430 } 431 if labels[1] != 0 { 432 t.Errorf("Expected pt %s is label 0, got %d\n", pts[1], labels[1]) 433 } 434 if labels[2] != 0 { 435 t.Errorf("Expected pt %s is label 0, got %d\n", pts[2], labels[2]) 436 } 437 pb3 := PositionedBlock{ 438 Block: *block2, 439 BCoord: dvid.ChunkPoint3d{4, 1, 2}.ToIZYXString(), 440 } 441 outOp.Process(&pb3) 442 443 if err := outOp.Finish(); err != nil { 444 t.Fatalf("error writing RLEs: %v\n", err) 445 } 446 output, err := ioutil.ReadAll(&buf) 447 if err != nil { 448 t.Fatalf("error on reading WriteRLEs: %v\n", err) 449 } 450 451 expectedNumRLEs := 64 * 64 * 16 452 if len(output) != expectedNumRLEs { 453 t.Fatalf("expected %d RLEs (%d bytes), got %d bytes\n", expectedNumRLEs/16, expectedNumRLEs, len(output)) 454 } 455 var rles dvid.RLEs 456 if err = rles.UnmarshalBinary(output); err != nil { 457 t.Fatalf("unable to parse binary RLEs: %v\n", err) 458 } 459 var i int 460 expected := make(dvid.RLEs, 64*64) 461 for z := int32(0); z < 64; z++ { 462 for y := int32(0); y < 32; y++ { 463 expected[i] = dvid.NewRLE(dvid.Point3d{128, y + 64, z + 128}, 192) 464 i++ 465 } 466 } 467 for z := int32(0); z < 64; z++ { 468 for y := int32(32); y < 64; y++ { 469 expected[i] = dvid.NewRLE(dvid.Point3d{128, y + 64, z + 128}, 128) 470 i++ 471 } 472 } 473 expected = expected.Normalize() 474 for i, rle := range rles.Normalize() { 475 if rle != expected[i] { 476 t.Errorf("Expected RLE %d: %s, got %s\n", i, expected[i], rle) 477 } 478 } 479 } 480 481 func TestBlockMerge(t *testing.T) { 482 numVoxels := 64 * 64 * 64 483 testvol := make([]uint64, numVoxels) 484 labels := make([]uint64, 5) 485 mergeSet := make(Set, 3) 486 for i := 0; i < 5; i++ { 487 var newlabel uint64 488 for { 489 newlabel = uint64(rand.Int63()) 490 ok := true 491 for j := 0; j < i; j++ { 492 if newlabel == labels[j] { 493 ok = false 494 } 495 } 496 if ok { 497 break 498 } 499 } 500 labels[i] = newlabel 501 if i > 1 { 502 mergeSet[labels[i]] = struct{}{} 503 } 504 } 505 for i := 0; i < numVoxels; i++ { 506 testvol[i] = labels[i%5] 507 } 508 block, err := MakeBlock(dvid.AliasUint64ToByte(testvol), dvid.Point3d{64, 64, 64}) 509 if err != nil { 510 t.Fatalf("error making block: %v\n", err) 511 } 512 runtime.KeepAlive(&testvol) 513 op := MergeOp{ 514 Target: labels[0], 515 Merged: mergeSet, 516 } 517 mergedBlock, err := block.MergeLabels(op) 518 if err != nil { 519 t.Fatalf("error merging block: %v\n", err) 520 } 521 volbytes, size := mergedBlock.MakeLabelVolume() 522 if size[0] != 64 || size[1] != 64 || size[2] != 64 { 523 t.Fatalf("bad merged block size returned: %s\n", size) 524 } 525 uint64arr, err := dvid.AliasByteToUint64(volbytes) 526 if err != nil { 527 t.Fatalf("error converting label byte array: %v\n", err) 528 } 529 for i := 0; i < numVoxels; i++ { 530 curlabel := uint64arr[i] 531 _, wasMerged := mergeSet[curlabel] 532 if wasMerged { 533 t.Fatalf("found voxel %d had label %d when it %s merged -> %d\n", i, curlabel, mergeSet, labels[0]) 534 } else if curlabel != labels[0] && curlabel != labels[1] { 535 t.Fatalf("found voxel %d had label %d which is not expected labels %d or %d\n", i, curlabel, labels[0], labels[1]) 536 } 537 } 538 runtime.KeepAlive(&volbytes) 539 } 540 541 func TestBlockReplaceLabel(t *testing.T) { 542 numVoxels := 64 * 64 * 64 543 testvol := make([]uint64, numVoxels) 544 for i := 0; i < numVoxels; i++ { 545 testvol[i] = 4 546 } 547 block, err := MakeBlock(dvid.AliasUint64ToByte(testvol), dvid.Point3d{64, 64, 64}) 548 if err != nil { 549 t.Fatalf("error making block: %v\n", err) 550 } 551 runtime.KeepAlive(&testvol) 552 _, replaceSize, err := block.ReplaceLabel(2, 1) 553 if err != nil { 554 t.Fatalf("error replacing block: %v\n", err) 555 } 556 if replaceSize != 0 { 557 t.Errorf("expected replaced # voxels to be zero, got %d\n", replaceSize) 558 } 559 tmpblock, replaceSize, err := block.ReplaceLabel(4, 1) 560 if err != nil { 561 t.Fatalf("error replacing block: %v\n", err) 562 } 563 if replaceSize != uint64(numVoxels) { 564 t.Errorf("expected replaced # voxels to be %d, got %d\n", numVoxels, replaceSize) 565 } 566 volbytes, size := tmpblock.MakeLabelVolume() 567 if size[0] != 64 || size[1] != 64 || size[2] != 64 { 568 t.Fatalf("bad replaced block size returned: %s\n", size) 569 } 570 uint64arr, err := dvid.AliasByteToUint64(volbytes) 571 if err != nil { 572 t.Fatalf("error converting label byte array: %v\n", err) 573 } 574 for i, label := range uint64arr { 575 if label != 1 { 576 t.Errorf("expected label 1 after replacement in voxel %d, got %d\n", i, label) 577 break 578 } 579 } 580 581 labels := make([]uint64, 5) 582 for i := 0; i < 5; i++ { 583 var newlabel uint64 584 for { 585 newlabel = uint64(rand.Int63()) 586 ok := true 587 for j := 0; j < i; j++ { 588 if newlabel == labels[j] { 589 ok = false 590 } 591 } 592 if ok { 593 break 594 } 595 } 596 labels[i] = newlabel 597 } 598 for i := 0; i < numVoxels; i++ { 599 testvol[i] = labels[i%4] 600 } 601 block, err = MakeBlock(dvid.AliasUint64ToByte(testvol), dvid.Point3d{64, 64, 64}) 602 if err != nil { 603 t.Fatalf("error making block: %v\n", err) 604 } 605 runtime.KeepAlive(&testvol) 606 tmpblock, replaceSize, err = block.ReplaceLabel(labels[0], labels[4]) 607 if err != nil { 608 t.Fatalf("error merging block: %v\n", err) 609 } 610 if replaceSize != uint64(numVoxels/4) { 611 t.Errorf("expected replaced # voxels with %d = %d, got %d\n", labels[0], numVoxels/4, replaceSize) 612 } 613 replacedBlock, replaceSize, err := tmpblock.ReplaceLabel(labels[1], labels[2]) 614 if err != nil { 615 t.Fatalf("error merging block: %v\n", err) 616 } 617 volbytes, size = replacedBlock.MakeLabelVolume() 618 if size[0] != 64 || size[1] != 64 || size[2] != 64 { 619 t.Fatalf("bad replaced block size returned: %s\n", size) 620 } 621 uint64arr, err = dvid.AliasByteToUint64(volbytes) 622 if err != nil { 623 t.Fatalf("error converting label byte array: %v\n", err) 624 } 625 for i := 0; i < numVoxels; i++ { 626 switch uint64arr[i] { 627 case labels[0]: 628 t.Fatalf("bad label at voxel %d: %d, should have been replaced by label %d\n", i, uint64arr[i], labels[4]) 629 case labels[1]: 630 t.Fatalf("bad label at voxel %d: %d, should have been replaced by label %d\n", i, uint64arr[i], labels[2]) 631 case labels[2], labels[3], labels[4]: 632 // good 633 default: 634 t.Fatalf("bad label at voxel %d: %d, not in expected labels %v\n", i, uint64arr[i], labels) 635 } 636 } 637 runtime.KeepAlive(&volbytes) 638 } 639 640 func TestBlockReplaceLabels(t *testing.T) { 641 numVoxels := 64 * 64 * 64 642 testvol := make([]uint64, numVoxels) 643 for i := 0; i < numVoxels; i++ { 644 testvol[i] = uint64(i) % 4 645 } 646 block, err := MakeBlock(dvid.AliasUint64ToByte(testvol), dvid.Point3d{64, 64, 64}) 647 if err != nil { 648 t.Fatalf("error making block: %v\n", err) 649 } 650 runtime.KeepAlive(&testvol) 651 mapping := map[uint64]uint64{ 652 0: 5, 653 1: 6, 654 2: 7, 655 3: 8, 656 } 657 replaceBlock, replaced, err := block.ReplaceLabels(mapping) 658 if err != nil { 659 t.Fatalf("error replacing block: %v\n", err) 660 } 661 if !replaced { 662 t.Errorf("expected replacement and got none\n") 663 } 664 volbytes, size := replaceBlock.MakeLabelVolume() 665 if size[0] != 64 || size[1] != 64 || size[2] != 64 { 666 t.Fatalf("bad replaced block size returned: %s\n", size) 667 } 668 uint64arr, err := dvid.AliasByteToUint64(volbytes) 669 if err != nil { 670 t.Fatalf("error converting label byte array: %v\n", err) 671 } 672 for i, label := range uint64arr { 673 if label != uint64(i%4)+5 { 674 t.Errorf("expected label %d after replacement in voxel %d, got %d\n", (i%4)+5, i, label) 675 break 676 } 677 } 678 runtime.KeepAlive(&volbytes) 679 } 680 681 func TestBlockSplitAndRLEs(t *testing.T) { 682 numVoxels := 32 * 32 * 32 683 testvol := make([]uint64, numVoxels) 684 for i := 0; i < numVoxels; i++ { 685 testvol[i] = uint64(i) 686 } 687 label := uint64(numVoxels * 10) // > previous labels 688 for x := 11; x < 31; x++ { 689 setLabel(testvol, 32, x, 8, 16, label) 690 } 691 block, err := MakeBlock(dvid.AliasUint64ToByte(testvol), dvid.Point3d{32, 32, 32}) 692 if err != nil { 693 t.Fatalf("error making block: %v\n", err) 694 } 695 runtime.KeepAlive(&testvol) 696 697 splitRLEs := dvid.RLEs{ 698 dvid.NewRLE(dvid.Point3d{81, 40, 80}, 6), 699 dvid.NewRLE(dvid.Point3d{90, 40, 80}, 3), 700 } 701 op := SplitOp{NewLabel: label + 1, Target: label, RLEs: splitRLEs} 702 pb := PositionedBlock{ 703 Block: *block, 704 BCoord: dvid.ChunkPoint3d{2, 1, 2}.ToIZYXString(), 705 } 706 split, keptSize, splitSize, err := pb.Split(op) 707 if err != nil { 708 t.Fatalf("error doing split: %v\n", err) 709 } 710 if keptSize != 11 { 711 t.Errorf("Expected kept size of 11, got %d\n", keptSize) 712 } 713 if splitSize != 9 { 714 t.Errorf("Expected split size of 9, got %d\n", splitSize) 715 } 716 717 var buf bytes.Buffer 718 lbls := Set{} 719 lbls[label] = struct{}{} 720 outOp := NewOutputOp(&buf) 721 go WriteRLEs(lbls, outOp, dvid.Bounds{}) 722 pb = PositionedBlock{ 723 Block: *split, 724 BCoord: dvid.ChunkPoint3d{2, 1, 2}.ToIZYXString(), 725 } 726 outOp.Process(&pb) 727 if err = outOp.Finish(); err != nil { 728 t.Fatalf("error writing RLEs: %v\n", err) 729 } 730 output, err := ioutil.ReadAll(&buf) 731 if err != nil { 732 t.Fatalf("error on reading WriteRLEs: %v\n", err) 733 } 734 if len(output) != 3*16 { 735 t.Fatalf("expected 3 RLEs (48 bytes), got %d bytes\n", len(output)) 736 } 737 var rles dvid.RLEs 738 if err = rles.UnmarshalBinary(output); err != nil { 739 t.Fatalf("unable to parse binary RLEs: %v\n", err) 740 } 741 expected := dvid.RLEs{ 742 dvid.NewRLE(dvid.Point3d{75, 40, 80}, 6), 743 dvid.NewRLE(dvid.Point3d{87, 40, 80}, 3), 744 dvid.NewRLE(dvid.Point3d{93, 40, 80}, 2), 745 } 746 for i, rle := range rles { 747 if rle != expected[i] { 748 t.Errorf("Expected RLE %d: %s, got %s\n", i, expected[i], rle) 749 } 750 } 751 } 752 753 func TestSolidBlockSize(t *testing.T) { 754 testLabel := uint64(9174832) 755 numVoxels := 64 * 64 * 64 756 blockVol := make([]uint64, numVoxels) 757 for i := 0; i < numVoxels; i++ { 758 blockVol[i] = testLabel 759 } 760 block, err := MakeBlock(dvid.AliasUint64ToByte(blockVol), dvid.Point3d{64, 64, 64}) 761 if err != nil { 762 t.Fatalf("error making block 0: %v\n", err) 763 } 764 runtime.KeepAlive(&blockVol) 765 compressed, err := block.MarshalBinary() 766 if err != nil { 767 t.Fatal(err) 768 } 769 if len(compressed) > 24 { 770 t.Errorf("solid block had %d bytes instead of optimal 24 bytes\n", len(compressed)) 771 } 772 solidBlock := MakeSolidBlock(testLabel, dvid.Point3d{64, 64, 64}) 773 uint64array, size := solidBlock.MakeLabelVolume() 774 if size[0] != 64 || size[1] != 64 || size[2] != 64 { 775 t.Fatalf("solid block didn't return appropriate size: %v\n", size) 776 } 777 uint64array2, size2 := block.MakeLabelVolume() 778 if size2[0] != 64 || size2[1] != 64 || size2[2] != 64 { 779 t.Fatalf("one label block didn't return appropriate size: %v\n", size2) 780 } 781 if !bytes.Equal(uint64array, uint64array2) { 782 t.Fatalf("solid block path does not equal single label encoded path\n") 783 } 784 labelVol, err := dvid.AliasByteToUint64(uint64array) 785 if err != nil { 786 t.Fatal(err) 787 } 788 for i := 0; i < numVoxels; i++ { 789 if labelVol[i] != testLabel { 790 t.Fatalf("uncompressed label volume had label %d instead of expected label %d @ position %d\n", labelVol[i], testLabel, i) 791 } 792 } 793 runtime.KeepAlive(&uint64array) 794 } 795 796 func TestBinaryBlocks(t *testing.T) { 797 numVoxels := 64 * 64 * 64 798 blockVol0 := make([]uint64, numVoxels) 799 blockVol1 := make([]uint64, numVoxels) 800 801 background := uint64(1000) 802 target := uint64(7) 803 var i, x, y, z int32 804 for z = 0; z < 64; z++ { 805 for y = 0; y < 64; y++ { 806 for x = 0; x < 64; x++ { 807 if x >= 23 && x <= 34 && y >= 37 && y <= 50 { 808 blockVol0[i] = target 809 } else { 810 blockVol0[i] = background 811 } 812 i++ 813 } 814 } 815 } 816 i = 0 817 for z = 0; z < 64; z++ { 818 for y = 0; y < 64; y++ { 819 for x = 0; x < 64; x++ { 820 if x >= 26 && x <= 31 && y >= 39 && y <= 45 { 821 blockVol1[i] = target 822 } else { 823 blockVol1[i] = background 824 } 825 i++ 826 } 827 } 828 } 829 830 block0, err := MakeBlock(dvid.AliasUint64ToByte(blockVol0), dvid.Point3d{64, 64, 64}) 831 if err != nil { 832 t.Fatalf("error making block 0: %v\n", err) 833 } 834 runtime.KeepAlive(&blockVol0) 835 block1, err := MakeBlock(dvid.AliasUint64ToByte(blockVol1), dvid.Point3d{64, 64, 64}) 836 if err != nil { 837 t.Fatalf("error making block 0: %v\n", err) 838 } 839 runtime.KeepAlive(&blockVol1) 840 841 pb0 := PositionedBlock{ 842 Block: *block0, 843 BCoord: dvid.ChunkPoint3d{1, 1, 1}.ToIZYXString(), 844 } 845 pb1 := PositionedBlock{ 846 Block: *block1, 847 BCoord: dvid.ChunkPoint3d{1, 1, 2}.ToIZYXString(), 848 } 849 850 var buf bytes.Buffer 851 lbls := Set{} 852 lbls[target] = struct{}{} 853 outOp := NewOutputOp(&buf) 854 go WriteBinaryBlocks(target, lbls, outOp, dvid.Bounds{}) 855 outOp.Process(&pb0) 856 outOp.Process(&pb1) 857 if err = outOp.Finish(); err != nil { 858 t.Fatalf("error writing binary blocks: %v\n", err) 859 } 860 got, err := ReceiveBinaryBlocks(&buf) 861 if err != nil { 862 t.Fatalf("error on reading binary blocks: %v\n", err) 863 } 864 if len(got) != 2 { 865 t.Fatalf("expected 2 binary blocks got %d\n", len(got)) 866 } 867 if got[0].Label != target { 868 t.Errorf("expected label %d for binary block 0, got %s\n", target, got[0]) 869 } 870 if got[1].Label != target { 871 t.Errorf("expected label %d for binary block 1, got %s\n", target, got[0]) 872 } 873 i = 0 874 for z = 0; z < 64; z++ { 875 for y = 0; y < 64; y++ { 876 for x = 0; x < 64; x++ { 877 if x >= 23 && x <= 34 && y >= 37 && y <= 50 { 878 if !got[0].Voxels[i] { 879 t.Fatalf("error in binary block 0: bad unset bit @ (%d,%d,%d)\n", x, y, z) 880 } 881 } else { 882 if got[0].Voxels[i] { 883 t.Fatalf("error in binary block 0: bad set bit @ (%d,%d,%d)\n", x, y, z) 884 } 885 } 886 i++ 887 } 888 } 889 } 890 i = 0 891 for z = 0; z < 64; z++ { 892 for y = 0; y < 64; y++ { 893 for x = 0; x < 64; x++ { 894 if x >= 26 && x <= 31 && y >= 39 && y <= 45 { 895 if !got[1].Voxels[i] { 896 t.Errorf("error in binary block 1: bad unset bit @ (%d,%d,%d)\n", x, y, z) 897 } 898 } else { 899 if got[1].Voxels[i] { 900 t.Errorf("error in binary block 1: bad set bit @ (%d,%d,%d)\n", x, y, z) 901 } 902 } 903 i++ 904 } 905 } 906 } 907 } 908 909 func testBlockPointLabels(t *testing.T, block *Block) { 910 labelData, _ := block.MakeLabelVolume() 911 pts := make([]dvid.Point3d, 5) 912 for n := 0; n < 1000; n++ { 913 for m := 0; m < 5; m++ { 914 pts[m] = dvid.Point3d{ 915 int32(rand.Int() % 64), 916 int32(rand.Int() % 64), 917 int32(rand.Int() % 64), 918 } 919 } 920 labels := block.GetPointLabels(pts) 921 for m, pt := range pts { 922 i := (pt[2]*64*64 + pt[1]*64 + pt[0]) * 8 923 label := binary.LittleEndian.Uint64(labelData[i : i+8]) 924 if label != labels[m] { 925 t.Fatalf("For pt %s expected label %d got label %d\n", pt, label, labels[m]) 926 } 927 } 928 } 929 } 930 931 func TestPointLabels(t *testing.T) { 932 var d testData 933 var block *Block 934 var err error 935 for _, filename := range testFiles { 936 d, err = loadData(filename) 937 if err != nil { 938 t.Fatal(err) 939 } 940 block, err = MakeBlock(d.b, dvid.Point3d{64, 64, 64}) 941 if err != nil { 942 t.Fatal(err) 943 } 944 testBlockPointLabels(t, block) 945 } 946 testBlockPointLabels(t, MakeSolidBlock(23, dvid.Point3d{64, 64, 64})) 947 } 948 949 func BenchmarkGoogleCompress(b *testing.B) { 950 d := make([]testData, len(testFiles)) 951 for i, filename := range testFiles { 952 var err error 953 d[i], err = loadData(filename) 954 if err != nil { 955 b.Fatal(err) 956 } 957 } 958 b.ResetTimer() 959 for i := 0; i < b.N; i++ { 960 _, err := oldCompressUint64(d[i%len(d)].u, dvid.Point3d{64, 64, 64}) 961 if err != nil { 962 b.Fatal(err) 963 } 964 } 965 } 966 967 func BenchmarkDvidCompress(b *testing.B) { 968 d := make([]testData, len(testFiles)) 969 for i, filename := range testFiles { 970 var err error 971 d[i], err = loadData(filename) 972 if err != nil { 973 b.Fatal(err) 974 } 975 } 976 b.ResetTimer() 977 for i := 0; i < b.N; i++ { 978 _, err := MakeBlock(d[i%len(d)].b, dvid.Point3d{64, 64, 64}) 979 if err != nil { 980 b.Fatal(err) 981 } 982 } 983 } 984 985 func BenchmarkDvidCompressGzip(b *testing.B) { 986 d := make([]testData, len(testFiles)) 987 for i, filename := range testFiles { 988 var err error 989 d[i], err = loadData(filename) 990 if err != nil { 991 b.Fatal(err) 992 } 993 } 994 b.ResetTimer() 995 for i := 0; i < b.N; i++ { 996 block, err := MakeBlock(d[i%len(d)].b, dvid.Point3d{64, 64, 64}) 997 if err != nil { 998 b.Fatal(err) 999 } 1000 var gzipOut bytes.Buffer 1001 zw := gzip.NewWriter(&gzipOut) 1002 if _, err = zw.Write(block.data); err != nil { 1003 b.Fatal(err) 1004 } 1005 zw.Flush() 1006 } 1007 } 1008 1009 func BenchmarkDvidCompressLZ4(b *testing.B) { 1010 d := make([]testData, len(testFiles)) 1011 for i, filename := range testFiles { 1012 var err error 1013 d[i], err = loadData(filename) 1014 if err != nil { 1015 b.Fatal(err) 1016 } 1017 } 1018 b.ResetTimer() 1019 for i := 0; i < b.N; i++ { 1020 block, err := MakeBlock(d[i%len(d)].b, dvid.Point3d{64, 64, 64}) 1021 if err != nil { 1022 b.Fatal(err) 1023 } 1024 var n int 1025 dvidLZ4 := make([]byte, lz4.CompressBound(block.data)) 1026 if n, err = lz4.Compress(block.data, dvidLZ4); err != nil { 1027 b.Fatal(err) 1028 } 1029 dvidLZ4 = dvidLZ4[:n] 1030 } 1031 } 1032 1033 func BenchmarkDvidMarshalGzip(b *testing.B) { 1034 var block [4]*Block 1035 for i, filename := range testFiles { 1036 d, err := loadData(filename) 1037 if err != nil { 1038 b.Fatal(err) 1039 } 1040 block[i%4], err = MakeBlock(d.b, dvid.Point3d{64, 64, 64}) 1041 if err != nil { 1042 b.Fatal(err) 1043 } 1044 } 1045 b.ResetTimer() 1046 var totbytes int 1047 for i := 0; i < b.N; i++ { 1048 var gzipOut bytes.Buffer 1049 zw := gzip.NewWriter(&gzipOut) 1050 if _, err := zw.Write(block[i%4].data); err != nil { 1051 b.Fatal(err) 1052 } 1053 zw.Flush() 1054 zw.Close() 1055 compressed := gzipOut.Bytes() 1056 totbytes += len(compressed) 1057 } 1058 } 1059 1060 func BenchmarkDvidUnmarshalGzip(b *testing.B) { 1061 var compressed [4][]byte 1062 for i, filename := range testFiles { 1063 d, err := loadData(filename) 1064 if err != nil { 1065 b.Fatal(err) 1066 } 1067 block, err := MakeBlock(d.b, dvid.Point3d{64, 64, 64}) 1068 if err != nil { 1069 b.Fatal(err) 1070 } 1071 var gzipOut bytes.Buffer 1072 zw := gzip.NewWriter(&gzipOut) 1073 if _, err = zw.Write(block.data); err != nil { 1074 b.Fatal(err) 1075 } 1076 zw.Flush() 1077 zw.Close() 1078 compressed[i%4] = make([]byte, gzipOut.Len()) 1079 copy(compressed[i%4], gzipOut.Bytes()) 1080 } 1081 b.ResetTimer() 1082 for i := 0; i < b.N; i++ { 1083 gzipIn := bytes.NewBuffer(compressed[i%4]) 1084 zr, err := gzip.NewReader(gzipIn) 1085 if err != nil { 1086 b.Fatal(err) 1087 } 1088 data, err := ioutil.ReadAll(zr) 1089 if err != nil { 1090 b.Fatal(err) 1091 } 1092 var block Block 1093 if err := block.UnmarshalBinary(data); err != nil { 1094 b.Fatal(err) 1095 } 1096 zr.Close() 1097 } 1098 } 1099 1100 func BenchmarkDvidMarshalLZ4(b *testing.B) { 1101 var block [4]*Block 1102 for i, filename := range testFiles { 1103 d, err := loadData(filename) 1104 if err != nil { 1105 b.Fatal(err) 1106 } 1107 block[i%4], err = MakeBlock(d.b, dvid.Point3d{64, 64, 64}) 1108 if err != nil { 1109 b.Fatal(err) 1110 } 1111 } 1112 b.ResetTimer() 1113 var totbytes int 1114 for i := 0; i < b.N; i++ { 1115 data := make([]byte, lz4.CompressBound(block[i%4].data)) 1116 var outsize int 1117 var err error 1118 if outsize, err = lz4.Compress(block[i%4].data, data); err != nil { 1119 b.Fatal(err) 1120 } 1121 compressed := data[:outsize] 1122 totbytes += len(compressed) 1123 } 1124 } 1125 1126 func BenchmarkDvidUnmarshalLZ4(b *testing.B) { 1127 var origsize [4]int 1128 var compressed [4][]byte 1129 for i, filename := range testFiles { 1130 d, err := loadData(filename) 1131 if err != nil { 1132 b.Fatal(err) 1133 } 1134 block, err := MakeBlock(d.b, dvid.Point3d{64, 64, 64}) 1135 if err != nil { 1136 b.Fatal(err) 1137 } 1138 data := make([]byte, lz4.CompressBound(block.data)) 1139 var outsize int 1140 if outsize, err = lz4.Compress(block.data, data); err != nil { 1141 b.Fatal(err) 1142 } 1143 compressed[i%4] = data[:outsize] 1144 origsize[i%4] = len(block.data) 1145 } 1146 b.ResetTimer() 1147 for i := 0; i < b.N; i++ { 1148 data := make([]byte, origsize[i%4]) 1149 if err := lz4.Uncompress(compressed[i%4], data); err != nil { 1150 b.Fatal(err) 1151 } 1152 var block Block 1153 if err := block.UnmarshalBinary(data); err != nil { 1154 b.Fatal(err) 1155 } 1156 } 1157 } 1158 1159 func BenchmarkGoogleReturnArray(b *testing.B) { 1160 var compressed [4][]uint32 1161 for i, filename := range testFiles { 1162 d, err := loadData(filename) 1163 if err != nil { 1164 b.Fatal(err) 1165 } 1166 compressed[i%4], err = oldCompressUint64(d.u, dvid.Point3d{64, 64, 64}) 1167 if err != nil { 1168 b.Fatal(err) 1169 } 1170 } 1171 b.ResetTimer() 1172 for i := 0; i < b.N; i++ { 1173 _, err := oldDecompressUint64(compressed[i%4], dvid.Point3d{64, 64, 64}) 1174 if err != nil { 1175 b.Fatal(err) 1176 } 1177 } 1178 } 1179 1180 func BenchmarkDvidReturnArray(b *testing.B) { 1181 var block [4]*Block 1182 for i, filename := range testFiles { 1183 d, err := loadData(filename) 1184 if err != nil { 1185 b.Fatal(err) 1186 } 1187 block[i%4], err = MakeBlock(d.b, dvid.Point3d{64, 64, 64}) 1188 if err != nil { 1189 b.Fatal(err) 1190 } 1191 } 1192 b.ResetTimer() 1193 for i := 0; i < b.N; i++ { 1194 labelarray, size := block[i%4].MakeLabelVolume() 1195 if int64(len(labelarray)) != size.Prod()*8 { 1196 b.Fatalf("expected label volume returned is %d bytes, got %d instead\n", size.Prod()*8, len(labelarray)) 1197 } 1198 } 1199 } 1200 1201 func BenchmarkPointLabels(b *testing.B) { 1202 var d testData 1203 numFiles := len(testFiles) 1204 blocks := make([]*Block, numFiles) 1205 var err error 1206 for i, filename := range testFiles { 1207 d, err = loadData(filename) 1208 if err != nil { 1209 b.Fatal(err) 1210 } 1211 blocks[i], err = MakeBlock(d.b, dvid.Point3d{64, 64, 64}) 1212 if err != nil { 1213 b.Fatal(err) 1214 } 1215 } 1216 b.ResetTimer() 1217 var x, y, z int32 1218 for i := 0; i < b.N; i++ { 1219 x = int32(i) % 64 1220 y = (x + 8) % 64 1221 z = (y + 8) % 64 1222 pts := []dvid.Point3d{ 1223 dvid.Point3d{x, y, z}, 1224 dvid.Point3d{y, x, z}, 1225 dvid.Point3d{z, x, y}, 1226 } 1227 for f := 0; f < numFiles; f++ { 1228 _ = blocks[f].GetPointLabels(pts) 1229 } 1230 } 1231 } 1232 1233 func BenchmarkOldPointLabels(b *testing.B) { 1234 var d testData 1235 numFiles := len(testFiles) 1236 blocks := make([]*Block, numFiles) 1237 var err error 1238 for i, filename := range testFiles { 1239 d, err = loadData(filename) 1240 if err != nil { 1241 b.Fatal(err) 1242 } 1243 blocks[i], err = MakeBlock(d.b, dvid.Point3d{64, 64, 64}) 1244 if err != nil { 1245 b.Fatal(err) 1246 } 1247 } 1248 b.ResetTimer() 1249 var x, y, z int32 1250 for i := 0; i < b.N; i++ { 1251 x = int32(i) % 64 1252 y = (x + 8) % 64 1253 z = (y + 8) % 64 1254 pts := []dvid.Point3d{ 1255 dvid.Point3d{x, y, z}, 1256 dvid.Point3d{y, x, z}, 1257 dvid.Point3d{z, x, y}, 1258 } 1259 for f := 0; f < numFiles; f++ { 1260 labelData, _ := blocks[f].MakeLabelVolume() 1261 for _, pt := range pts { 1262 i := (pt[2]*64*64 + pt[1]*64 + pt[0]) * 8 1263 _ = binary.LittleEndian.Uint64(labelData[i : i+8]) 1264 } 1265 } 1266 } 1267 }