github.com/m10x/go/src@v0.0.0-20220112094212-ba61592315da/runtime/hash_test.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime_test 6 7 import ( 8 "fmt" 9 "math" 10 "math/rand" 11 . "runtime" 12 "strings" 13 "testing" 14 "unsafe" 15 ) 16 17 func TestMemHash32Equality(t *testing.T) { 18 if *UseAeshash { 19 t.Skip("skipping since AES hash implementation is used") 20 } 21 var b [4]byte 22 r := rand.New(rand.NewSource(1234)) 23 seed := uintptr(r.Uint64()) 24 for i := 0; i < 100; i++ { 25 randBytes(r, b[:]) 26 got := MemHash32(unsafe.Pointer(&b), seed) 27 want := MemHash(unsafe.Pointer(&b), seed, 4) 28 if got != want { 29 t.Errorf("MemHash32(%x, %v) = %v; want %v", b, seed, got, want) 30 } 31 } 32 } 33 34 func TestMemHash64Equality(t *testing.T) { 35 if *UseAeshash { 36 t.Skip("skipping since AES hash implementation is used") 37 } 38 var b [8]byte 39 r := rand.New(rand.NewSource(1234)) 40 seed := uintptr(r.Uint64()) 41 for i := 0; i < 100; i++ { 42 randBytes(r, b[:]) 43 got := MemHash64(unsafe.Pointer(&b), seed) 44 want := MemHash(unsafe.Pointer(&b), seed, 8) 45 if got != want { 46 t.Errorf("MemHash64(%x, %v) = %v; want %v", b, seed, got, want) 47 } 48 } 49 } 50 51 // Smhasher is a torture test for hash functions. 52 // https://code.google.com/p/smhasher/ 53 // This code is a port of some of the Smhasher tests to Go. 54 // 55 // The current AES hash function passes Smhasher. Our fallback 56 // hash functions don't, so we only enable the difficult tests when 57 // we know the AES implementation is available. 58 59 // Sanity checks. 60 // hash should not depend on values outside key. 61 // hash should not depend on alignment. 62 func TestSmhasherSanity(t *testing.T) { 63 r := rand.New(rand.NewSource(1234)) 64 const REP = 10 65 const KEYMAX = 128 66 const PAD = 16 67 const OFFMAX = 16 68 for k := 0; k < REP; k++ { 69 for n := 0; n < KEYMAX; n++ { 70 for i := 0; i < OFFMAX; i++ { 71 var b [KEYMAX + OFFMAX + 2*PAD]byte 72 var c [KEYMAX + OFFMAX + 2*PAD]byte 73 randBytes(r, b[:]) 74 randBytes(r, c[:]) 75 copy(c[PAD+i:PAD+i+n], b[PAD:PAD+n]) 76 if BytesHash(b[PAD:PAD+n], 0) != BytesHash(c[PAD+i:PAD+i+n], 0) { 77 t.Errorf("hash depends on bytes outside key") 78 } 79 } 80 } 81 } 82 } 83 84 type HashSet struct { 85 m map[uintptr]struct{} // set of hashes added 86 n int // number of hashes added 87 } 88 89 func newHashSet() *HashSet { 90 return &HashSet{make(map[uintptr]struct{}), 0} 91 } 92 func (s *HashSet) add(h uintptr) { 93 s.m[h] = struct{}{} 94 s.n++ 95 } 96 func (s *HashSet) addS(x string) { 97 s.add(StringHash(x, 0)) 98 } 99 func (s *HashSet) addB(x []byte) { 100 s.add(BytesHash(x, 0)) 101 } 102 func (s *HashSet) addS_seed(x string, seed uintptr) { 103 s.add(StringHash(x, seed)) 104 } 105 func (s *HashSet) check(t *testing.T) { 106 const SLOP = 50.0 107 collisions := s.n - len(s.m) 108 pairs := int64(s.n) * int64(s.n-1) / 2 109 expected := float64(pairs) / math.Pow(2.0, float64(hashSize)) 110 stddev := math.Sqrt(expected) 111 if float64(collisions) > expected+SLOP*(3*stddev+1) { 112 t.Errorf("unexpected number of collisions: got=%d mean=%f stddev=%f threshold=%f", collisions, expected, stddev, expected+SLOP*(3*stddev+1)) 113 } 114 } 115 116 // a string plus adding zeros must make distinct hashes 117 func TestSmhasherAppendedZeros(t *testing.T) { 118 s := "hello" + strings.Repeat("\x00", 256) 119 h := newHashSet() 120 for i := 0; i <= len(s); i++ { 121 h.addS(s[:i]) 122 } 123 h.check(t) 124 } 125 126 // All 0-3 byte strings have distinct hashes. 127 func TestSmhasherSmallKeys(t *testing.T) { 128 h := newHashSet() 129 var b [3]byte 130 for i := 0; i < 256; i++ { 131 b[0] = byte(i) 132 h.addB(b[:1]) 133 for j := 0; j < 256; j++ { 134 b[1] = byte(j) 135 h.addB(b[:2]) 136 if !testing.Short() { 137 for k := 0; k < 256; k++ { 138 b[2] = byte(k) 139 h.addB(b[:3]) 140 } 141 } 142 } 143 } 144 h.check(t) 145 } 146 147 // Different length strings of all zeros have distinct hashes. 148 func TestSmhasherZeros(t *testing.T) { 149 N := 256 * 1024 150 if testing.Short() { 151 N = 1024 152 } 153 h := newHashSet() 154 b := make([]byte, N) 155 for i := 0; i <= N; i++ { 156 h.addB(b[:i]) 157 } 158 h.check(t) 159 } 160 161 // Strings with up to two nonzero bytes all have distinct hashes. 162 func TestSmhasherTwoNonzero(t *testing.T) { 163 if GOARCH == "wasm" { 164 t.Skip("Too slow on wasm") 165 } 166 if testing.Short() { 167 t.Skip("Skipping in short mode") 168 } 169 h := newHashSet() 170 for n := 2; n <= 16; n++ { 171 twoNonZero(h, n) 172 } 173 h.check(t) 174 } 175 func twoNonZero(h *HashSet, n int) { 176 b := make([]byte, n) 177 178 // all zero 179 h.addB(b) 180 181 // one non-zero byte 182 for i := 0; i < n; i++ { 183 for x := 1; x < 256; x++ { 184 b[i] = byte(x) 185 h.addB(b) 186 b[i] = 0 187 } 188 } 189 190 // two non-zero bytes 191 for i := 0; i < n; i++ { 192 for x := 1; x < 256; x++ { 193 b[i] = byte(x) 194 for j := i + 1; j < n; j++ { 195 for y := 1; y < 256; y++ { 196 b[j] = byte(y) 197 h.addB(b) 198 b[j] = 0 199 } 200 } 201 b[i] = 0 202 } 203 } 204 } 205 206 // Test strings with repeats, like "abcdabcdabcdabcd..." 207 func TestSmhasherCyclic(t *testing.T) { 208 if testing.Short() { 209 t.Skip("Skipping in short mode") 210 } 211 r := rand.New(rand.NewSource(1234)) 212 const REPEAT = 8 213 const N = 1000000 214 for n := 4; n <= 12; n++ { 215 h := newHashSet() 216 b := make([]byte, REPEAT*n) 217 for i := 0; i < N; i++ { 218 b[0] = byte(i * 79 % 97) 219 b[1] = byte(i * 43 % 137) 220 b[2] = byte(i * 151 % 197) 221 b[3] = byte(i * 199 % 251) 222 randBytes(r, b[4:n]) 223 for j := n; j < n*REPEAT; j++ { 224 b[j] = b[j-n] 225 } 226 h.addB(b) 227 } 228 h.check(t) 229 } 230 } 231 232 // Test strings with only a few bits set 233 func TestSmhasherSparse(t *testing.T) { 234 if GOARCH == "wasm" { 235 t.Skip("Too slow on wasm") 236 } 237 if testing.Short() { 238 t.Skip("Skipping in short mode") 239 } 240 sparse(t, 32, 6) 241 sparse(t, 40, 6) 242 sparse(t, 48, 5) 243 sparse(t, 56, 5) 244 sparse(t, 64, 5) 245 sparse(t, 96, 4) 246 sparse(t, 256, 3) 247 sparse(t, 2048, 2) 248 } 249 func sparse(t *testing.T, n int, k int) { 250 b := make([]byte, n/8) 251 h := newHashSet() 252 setbits(h, b, 0, k) 253 h.check(t) 254 } 255 256 // set up to k bits at index i and greater 257 func setbits(h *HashSet, b []byte, i int, k int) { 258 h.addB(b) 259 if k == 0 { 260 return 261 } 262 for j := i; j < len(b)*8; j++ { 263 b[j/8] |= byte(1 << uint(j&7)) 264 setbits(h, b, j+1, k-1) 265 b[j/8] &= byte(^(1 << uint(j&7))) 266 } 267 } 268 269 // Test all possible combinations of n blocks from the set s. 270 // "permutation" is a bad name here, but it is what Smhasher uses. 271 func TestSmhasherPermutation(t *testing.T) { 272 if GOARCH == "wasm" { 273 t.Skip("Too slow on wasm") 274 } 275 if testing.Short() { 276 t.Skip("Skipping in short mode") 277 } 278 permutation(t, []uint32{0, 1, 2, 3, 4, 5, 6, 7}, 8) 279 permutation(t, []uint32{0, 1 << 29, 2 << 29, 3 << 29, 4 << 29, 5 << 29, 6 << 29, 7 << 29}, 8) 280 permutation(t, []uint32{0, 1}, 20) 281 permutation(t, []uint32{0, 1 << 31}, 20) 282 permutation(t, []uint32{0, 1, 2, 3, 4, 5, 6, 7, 1 << 29, 2 << 29, 3 << 29, 4 << 29, 5 << 29, 6 << 29, 7 << 29}, 6) 283 } 284 func permutation(t *testing.T, s []uint32, n int) { 285 b := make([]byte, n*4) 286 h := newHashSet() 287 genPerm(h, b, s, 0) 288 h.check(t) 289 } 290 func genPerm(h *HashSet, b []byte, s []uint32, n int) { 291 h.addB(b[:n]) 292 if n == len(b) { 293 return 294 } 295 for _, v := range s { 296 b[n] = byte(v) 297 b[n+1] = byte(v >> 8) 298 b[n+2] = byte(v >> 16) 299 b[n+3] = byte(v >> 24) 300 genPerm(h, b, s, n+4) 301 } 302 } 303 304 type Key interface { 305 clear() // set bits all to 0 306 random(r *rand.Rand) // set key to something random 307 bits() int // how many bits key has 308 flipBit(i int) // flip bit i of the key 309 hash() uintptr // hash the key 310 name() string // for error reporting 311 } 312 313 type BytesKey struct { 314 b []byte 315 } 316 317 func (k *BytesKey) clear() { 318 for i := range k.b { 319 k.b[i] = 0 320 } 321 } 322 func (k *BytesKey) random(r *rand.Rand) { 323 randBytes(r, k.b) 324 } 325 func (k *BytesKey) bits() int { 326 return len(k.b) * 8 327 } 328 func (k *BytesKey) flipBit(i int) { 329 k.b[i>>3] ^= byte(1 << uint(i&7)) 330 } 331 func (k *BytesKey) hash() uintptr { 332 return BytesHash(k.b, 0) 333 } 334 func (k *BytesKey) name() string { 335 return fmt.Sprintf("bytes%d", len(k.b)) 336 } 337 338 type Int32Key struct { 339 i uint32 340 } 341 342 func (k *Int32Key) clear() { 343 k.i = 0 344 } 345 func (k *Int32Key) random(r *rand.Rand) { 346 k.i = r.Uint32() 347 } 348 func (k *Int32Key) bits() int { 349 return 32 350 } 351 func (k *Int32Key) flipBit(i int) { 352 k.i ^= 1 << uint(i) 353 } 354 func (k *Int32Key) hash() uintptr { 355 return Int32Hash(k.i, 0) 356 } 357 func (k *Int32Key) name() string { 358 return "int32" 359 } 360 361 type Int64Key struct { 362 i uint64 363 } 364 365 func (k *Int64Key) clear() { 366 k.i = 0 367 } 368 func (k *Int64Key) random(r *rand.Rand) { 369 k.i = uint64(r.Uint32()) + uint64(r.Uint32())<<32 370 } 371 func (k *Int64Key) bits() int { 372 return 64 373 } 374 func (k *Int64Key) flipBit(i int) { 375 k.i ^= 1 << uint(i) 376 } 377 func (k *Int64Key) hash() uintptr { 378 return Int64Hash(k.i, 0) 379 } 380 func (k *Int64Key) name() string { 381 return "int64" 382 } 383 384 type EfaceKey struct { 385 i any 386 } 387 388 func (k *EfaceKey) clear() { 389 k.i = nil 390 } 391 func (k *EfaceKey) random(r *rand.Rand) { 392 k.i = uint64(r.Int63()) 393 } 394 func (k *EfaceKey) bits() int { 395 // use 64 bits. This tests inlined interfaces 396 // on 64-bit targets and indirect interfaces on 397 // 32-bit targets. 398 return 64 399 } 400 func (k *EfaceKey) flipBit(i int) { 401 k.i = k.i.(uint64) ^ uint64(1)<<uint(i) 402 } 403 func (k *EfaceKey) hash() uintptr { 404 return EfaceHash(k.i, 0) 405 } 406 func (k *EfaceKey) name() string { 407 return "Eface" 408 } 409 410 type IfaceKey struct { 411 i interface { 412 F() 413 } 414 } 415 type fInter uint64 416 417 func (x fInter) F() { 418 } 419 420 func (k *IfaceKey) clear() { 421 k.i = nil 422 } 423 func (k *IfaceKey) random(r *rand.Rand) { 424 k.i = fInter(r.Int63()) 425 } 426 func (k *IfaceKey) bits() int { 427 // use 64 bits. This tests inlined interfaces 428 // on 64-bit targets and indirect interfaces on 429 // 32-bit targets. 430 return 64 431 } 432 func (k *IfaceKey) flipBit(i int) { 433 k.i = k.i.(fInter) ^ fInter(1)<<uint(i) 434 } 435 func (k *IfaceKey) hash() uintptr { 436 return IfaceHash(k.i, 0) 437 } 438 func (k *IfaceKey) name() string { 439 return "Iface" 440 } 441 442 // Flipping a single bit of a key should flip each output bit with 50% probability. 443 func TestSmhasherAvalanche(t *testing.T) { 444 if GOARCH == "wasm" { 445 t.Skip("Too slow on wasm") 446 } 447 if testing.Short() { 448 t.Skip("Skipping in short mode") 449 } 450 avalancheTest1(t, &BytesKey{make([]byte, 2)}) 451 avalancheTest1(t, &BytesKey{make([]byte, 4)}) 452 avalancheTest1(t, &BytesKey{make([]byte, 8)}) 453 avalancheTest1(t, &BytesKey{make([]byte, 16)}) 454 avalancheTest1(t, &BytesKey{make([]byte, 32)}) 455 avalancheTest1(t, &BytesKey{make([]byte, 200)}) 456 avalancheTest1(t, &Int32Key{}) 457 avalancheTest1(t, &Int64Key{}) 458 avalancheTest1(t, &EfaceKey{}) 459 avalancheTest1(t, &IfaceKey{}) 460 } 461 func avalancheTest1(t *testing.T, k Key) { 462 const REP = 100000 463 r := rand.New(rand.NewSource(1234)) 464 n := k.bits() 465 466 // grid[i][j] is a count of whether flipping 467 // input bit i affects output bit j. 468 grid := make([][hashSize]int, n) 469 470 for z := 0; z < REP; z++ { 471 // pick a random key, hash it 472 k.random(r) 473 h := k.hash() 474 475 // flip each bit, hash & compare the results 476 for i := 0; i < n; i++ { 477 k.flipBit(i) 478 d := h ^ k.hash() 479 k.flipBit(i) 480 481 // record the effects of that bit flip 482 g := &grid[i] 483 for j := 0; j < hashSize; j++ { 484 g[j] += int(d & 1) 485 d >>= 1 486 } 487 } 488 } 489 490 // Each entry in the grid should be about REP/2. 491 // More precisely, we did N = k.bits() * hashSize experiments where 492 // each is the sum of REP coin flips. We want to find bounds on the 493 // sum of coin flips such that a truly random experiment would have 494 // all sums inside those bounds with 99% probability. 495 N := n * hashSize 496 var c float64 497 // find c such that Prob(mean-c*stddev < x < mean+c*stddev)^N > .9999 498 for c = 0.0; math.Pow(math.Erf(c/math.Sqrt(2)), float64(N)) < .9999; c += .1 { 499 } 500 c *= 4.0 // allowed slack - we don't need to be perfectly random 501 mean := .5 * REP 502 stddev := .5 * math.Sqrt(REP) 503 low := int(mean - c*stddev) 504 high := int(mean + c*stddev) 505 for i := 0; i < n; i++ { 506 for j := 0; j < hashSize; j++ { 507 x := grid[i][j] 508 if x < low || x > high { 509 t.Errorf("bad bias for %s bit %d -> bit %d: %d/%d\n", k.name(), i, j, x, REP) 510 } 511 } 512 } 513 } 514 515 // All bit rotations of a set of distinct keys 516 func TestSmhasherWindowed(t *testing.T) { 517 t.Logf("32 bit keys") 518 windowed(t, &Int32Key{}) 519 t.Logf("64 bit keys") 520 windowed(t, &Int64Key{}) 521 t.Logf("string keys") 522 windowed(t, &BytesKey{make([]byte, 128)}) 523 } 524 func windowed(t *testing.T, k Key) { 525 if GOARCH == "wasm" { 526 t.Skip("Too slow on wasm") 527 } 528 if testing.Short() { 529 t.Skip("Skipping in short mode") 530 } 531 const BITS = 16 532 533 for r := 0; r < k.bits(); r++ { 534 h := newHashSet() 535 for i := 0; i < 1<<BITS; i++ { 536 k.clear() 537 for j := 0; j < BITS; j++ { 538 if i>>uint(j)&1 != 0 { 539 k.flipBit((j + r) % k.bits()) 540 } 541 } 542 h.add(k.hash()) 543 } 544 h.check(t) 545 } 546 } 547 548 // All keys of the form prefix + [A-Za-z0-9]*N + suffix. 549 func TestSmhasherText(t *testing.T) { 550 if testing.Short() { 551 t.Skip("Skipping in short mode") 552 } 553 text(t, "Foo", "Bar") 554 text(t, "FooBar", "") 555 text(t, "", "FooBar") 556 } 557 func text(t *testing.T, prefix, suffix string) { 558 const N = 4 559 const S = "ABCDEFGHIJKLMNOPQRSTabcdefghijklmnopqrst0123456789" 560 const L = len(S) 561 b := make([]byte, len(prefix)+N+len(suffix)) 562 copy(b, prefix) 563 copy(b[len(prefix)+N:], suffix) 564 h := newHashSet() 565 c := b[len(prefix):] 566 for i := 0; i < L; i++ { 567 c[0] = S[i] 568 for j := 0; j < L; j++ { 569 c[1] = S[j] 570 for k := 0; k < L; k++ { 571 c[2] = S[k] 572 for x := 0; x < L; x++ { 573 c[3] = S[x] 574 h.addB(b) 575 } 576 } 577 } 578 } 579 h.check(t) 580 } 581 582 // Make sure different seed values generate different hashes. 583 func TestSmhasherSeed(t *testing.T) { 584 h := newHashSet() 585 const N = 100000 586 s := "hello" 587 for i := 0; i < N; i++ { 588 h.addS_seed(s, uintptr(i)) 589 } 590 h.check(t) 591 } 592 593 // size of the hash output (32 or 64 bits) 594 const hashSize = 32 + int(^uintptr(0)>>63<<5) 595 596 func randBytes(r *rand.Rand, b []byte) { 597 for i := range b { 598 b[i] = byte(r.Uint32()) 599 } 600 } 601 602 func benchmarkHash(b *testing.B, n int) { 603 s := strings.Repeat("A", n) 604 605 for i := 0; i < b.N; i++ { 606 StringHash(s, 0) 607 } 608 b.SetBytes(int64(n)) 609 } 610 611 func BenchmarkHash5(b *testing.B) { benchmarkHash(b, 5) } 612 func BenchmarkHash16(b *testing.B) { benchmarkHash(b, 16) } 613 func BenchmarkHash64(b *testing.B) { benchmarkHash(b, 64) } 614 func BenchmarkHash1024(b *testing.B) { benchmarkHash(b, 1024) } 615 func BenchmarkHash65536(b *testing.B) { benchmarkHash(b, 65536) } 616 617 func TestArrayHash(t *testing.T) { 618 // Make sure that "" in arrays hash correctly. The hash 619 // should at least scramble the input seed so that, e.g., 620 // {"","foo"} and {"foo",""} have different hashes. 621 622 // If the hash is bad, then all (8 choose 4) = 70 keys 623 // have the same hash. If so, we allocate 70/8 = 8 624 // overflow buckets. If the hash is good we don't 625 // normally allocate any overflow buckets, and the 626 // probability of even one or two overflows goes down rapidly. 627 // (There is always 1 allocation of the bucket array. The map 628 // header is allocated on the stack.) 629 f := func() { 630 // Make the key type at most 128 bytes. Otherwise, 631 // we get an allocation per key. 632 type key [8]string 633 m := make(map[key]bool, 70) 634 635 // fill m with keys that have 4 "foo"s and 4 ""s. 636 for i := 0; i < 256; i++ { 637 var k key 638 cnt := 0 639 for j := uint(0); j < 8; j++ { 640 if i>>j&1 != 0 { 641 k[j] = "foo" 642 cnt++ 643 } 644 } 645 if cnt == 4 { 646 m[k] = true 647 } 648 } 649 if len(m) != 70 { 650 t.Errorf("bad test: (8 choose 4) should be 70, not %d", len(m)) 651 } 652 } 653 if n := testing.AllocsPerRun(10, f); n > 6 { 654 t.Errorf("too many allocs %f - hash not balanced", n) 655 } 656 } 657 func TestStructHash(t *testing.T) { 658 // See the comment in TestArrayHash. 659 f := func() { 660 type key struct { 661 a, b, c, d, e, f, g, h string 662 } 663 m := make(map[key]bool, 70) 664 665 // fill m with keys that have 4 "foo"s and 4 ""s. 666 for i := 0; i < 256; i++ { 667 var k key 668 cnt := 0 669 if i&1 != 0 { 670 k.a = "foo" 671 cnt++ 672 } 673 if i&2 != 0 { 674 k.b = "foo" 675 cnt++ 676 } 677 if i&4 != 0 { 678 k.c = "foo" 679 cnt++ 680 } 681 if i&8 != 0 { 682 k.d = "foo" 683 cnt++ 684 } 685 if i&16 != 0 { 686 k.e = "foo" 687 cnt++ 688 } 689 if i&32 != 0 { 690 k.f = "foo" 691 cnt++ 692 } 693 if i&64 != 0 { 694 k.g = "foo" 695 cnt++ 696 } 697 if i&128 != 0 { 698 k.h = "foo" 699 cnt++ 700 } 701 if cnt == 4 { 702 m[k] = true 703 } 704 } 705 if len(m) != 70 { 706 t.Errorf("bad test: (8 choose 4) should be 70, not %d", len(m)) 707 } 708 } 709 if n := testing.AllocsPerRun(10, f); n > 6 { 710 t.Errorf("too many allocs %f - hash not balanced", n) 711 } 712 } 713 714 var sink uint64 715 716 func BenchmarkAlignedLoad(b *testing.B) { 717 var buf [16]byte 718 p := unsafe.Pointer(&buf[0]) 719 var s uint64 720 for i := 0; i < b.N; i++ { 721 s += ReadUnaligned64(p) 722 } 723 sink = s 724 } 725 726 func BenchmarkUnalignedLoad(b *testing.B) { 727 var buf [16]byte 728 p := unsafe.Pointer(&buf[1]) 729 var s uint64 730 for i := 0; i < b.N; i++ { 731 s += ReadUnaligned64(p) 732 } 733 sink = s 734 } 735 736 func TestCollisions(t *testing.T) { 737 if testing.Short() { 738 t.Skip("Skipping in short mode") 739 } 740 for i := 0; i < 16; i++ { 741 for j := 0; j < 16; j++ { 742 if j == i { 743 continue 744 } 745 var a [16]byte 746 m := make(map[uint16]struct{}, 1<<16) 747 for n := 0; n < 1<<16; n++ { 748 a[i] = byte(n) 749 a[j] = byte(n >> 8) 750 m[uint16(BytesHash(a[:], 0))] = struct{}{} 751 } 752 if len(m) <= 1<<15 { 753 t.Errorf("too many collisions i=%d j=%d outputs=%d out of 65536\n", i, j, len(m)) 754 } 755 } 756 } 757 }