Skip to content

kv: add simple bulk put routines for vectorized insert#96237

Merged
craig[bot] merged 1 commit intocockroachdb:masterfrom
cucaroach:bulk-put-apis
Mar 2, 2023
Merged

kv: add simple bulk put routines for vectorized insert#96237
craig[bot] merged 1 commit intocockroachdb:masterfrom
cucaroach:bulk-put-apis

Conversation

@cucaroach
Copy link
Copy Markdown
Contributor

These are simple analogs to existing APIs that do all the memory
allocations in bulk.

Epic: CRDB-18892
Informs: #91831
Release note: None

@blathers-crl
Copy link
Copy Markdown

blathers-crl bot commented Jan 30, 2023

It looks like your PR touches production code but doesn't add or edit any test code. Did you consider adding tests to your PR?

🦉 Hoot! I am a Blathers, a bot for CockroachDB. My owner is dev-inf.

@cockroach-teamcity
Copy link
Copy Markdown
Member

This change is Reviewable

@cucaroach cucaroach force-pushed the bulk-put-apis branch 2 times, most recently from 27f55d3 to 540f632 Compare January 31, 2023 04:04
@cucaroach cucaroach changed the title kv: add simple bulk put routines for new vectorized insert kv: add simple bulk put routines for vectorized insert Jan 31, 2023
@cucaroach cucaroach requested review from a team and msirek January 31, 2023 12:38
@cucaroach cucaroach marked this pull request as ready for review January 31, 2023 12:38
@cucaroach cucaroach requested a review from a team as a code owner January 31, 2023 12:38
@knz knz requested a review from nvb February 1, 2023 13:50
@knz
Copy link
Copy Markdown
Contributor

knz commented Feb 1, 2023

@nvanbenschoten i think this PR is down your alley

Copy link
Copy Markdown
Contributor

@nvb nvb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 1 of 1 files at r1, all commit messages.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @cucaroach and @msirek)


pkg/kv/batch.go line 430 at r1 (raw file):

}

// PutBytes allows multiple Bytes value type puts to be added to the batch.

nit: s/Bytes/[]byte/g


pkg/kv/batch.go line 430 at r1 (raw file):

}

// PutBytes allows multiple Bytes value type puts to be added to the batch.

Can we add testing for these new methods?


pkg/kv/batch.go line 435 at r1 (raw file):

	b.bulkRequest(keys, values, func(i int, k roachpb.Key, v []byte) (roachpb.Request, int) {
		pr := &reqs[i]
		pr.RequestHeader.Key = k

nit: Isn't RequestHeader embedded?


pkg/kv/batch.go line 436 at r1 (raw file):

		pr := &reqs[i]
		pr.RequestHeader.Key = k
		pr.Value.SetBytes(v)

Should we be setting Value checksums here? Like we do in roachpb.NewPut.


pkg/kv/batch.go line 441 at r1 (raw file):

}

// InitPutBytes allows multiple Bytes value type puts to be added to the batch.

nit: could you move the two batch InitPut methods below (*Batch).InitPut?


pkg/kv/batch.go line 577 at r1 (raw file):

		b.Results = make([]Result, 0, len(keys))
	}
	count := 0

Why can't we use bulkRequests in this case? Is the contract too rigid? Can we fix that?


pkg/kv/batch.go line 996 at r1 (raw file):

}

func (b *Batch) bulkRequest(

Should we assert that len(keys) == len(values)?


pkg/kv/batch.go line 999 at r1 (raw file):

	keys []roachpb.Key,
	values [][]byte,
	valFactory func(int, roachpb.Key, []byte) (roachpb.Request, int),

reqFactory?


pkg/kv/batch.go line 999 at r1 (raw file):

	keys []roachpb.Key,
	values [][]byte,
	valFactory func(int, roachpb.Key, []byte) (roachpb.Request, int),

Let's give the int return value a name so that the contract is clear.

Along the same lines, let's name the params. The role of the int param isn't obvious.


pkg/kv/batch.go line 1007 at r1 (raw file):

	count := 0
	for i, key := range keys {
		// Ignore nil keys

This necessitates the count tracking, separate from i. Is it needed? Why would we ever pass in a nil key?


pkg/kv/batch.go line 1014 at r1 (raw file):

		reqs[count], numBytes = valFactory(count, key, values[i])
		b.approxMutationReqBytes += len(key) + numBytes
		b.initResult(1, 1, notRaw, nil)

Should we be calling this once per batch of Puts? Like we do in (*Batch).Del?

Copy link
Copy Markdown
Contributor Author

@cucaroach cucaroach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all the helpful review comments! I think I addressed everything, let me know if you think we more tests.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @msirek and @nvanbenschoten)


pkg/kv/batch.go line 430 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Can we add testing for these new methods?

Yes! Looks like db_test.go would be a good place for them.


pkg/kv/batch.go line 435 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

nit: Isn't RequestHeader embedded?

I'm not sure what this means. Oh you're saying I can just leave off the RequestHeader yes?


pkg/kv/batch.go line 436 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Should we be setting Value checksums here? Like we do in roachpb.NewPut.

I assume we should, is there something I can use to test that the checksums are set and correct?


pkg/kv/batch.go line 577 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Why can't we use bulkRequests in this case? Is the contract too rigid? Can we fix that?

Good idea, I gave up to easily.


pkg/kv/batch.go line 996 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Should we assert that len(keys) == len(values)?

We could, I'm still unclear if we


pkg/kv/batch.go line 1007 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

This necessitates the count tracking, separate from i. Is it needed? Why would we ever pass in a nil key?

So basically we re-use slices across each index and due to partial indexes there are "holes" where we elide KVs that fail the partial index predicate. Basically nil keys is my way of avoiding doing this separate count tracking and compaction at the encoder level and letting it happen here at the KV API boundary where I think its cheaper because we're reformulating everything anyways. Its a little sleazy but I think its kinda the "vector" way, akin to how coldata.Batches utilize selection vectors.


pkg/kv/batch.go line 1014 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Should we be calling this once per batch of Puts? Like we do in (*Batch).Del?

I don't think so, at least not without changing all the result processing code since, Del doesn't seem to care about the result of each individual delete so it has one result with N calls? Maybe I'm missing something but I think I had to do it this way to get a result per request.

Copy link
Copy Markdown
Contributor Author

@cucaroach cucaroach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @msirek and @nvanbenschoten)


pkg/kv/batch.go line 996 at r1 (raw file):

Previously, cucaroach (Tommy Reilly) wrote…

We could, I'm still unclear if we

Finishing thought ... I'm unsure where its a good idea to add assertion checks for things that should never happen when Go will generate good enough error messages to clue in future developers who introduce breakages. Sometimes I see checks like this in crdb_test blocks. Curious what your thoughts are.

Copy link
Copy Markdown
Contributor Author

@cucaroach cucaroach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @msirek and @nvanbenschoten)


pkg/kv/batch.go line 1014 at r1 (raw file):

Previously, cucaroach (Tommy Reilly) wrote…

I don't think so, at least not without changing all the result processing code since, Del doesn't seem to care about the result of each individual delete so it has one result with N calls? Maybe I'm missing something but I think I had to do it this way to get a result per request.

I do think there's room for improvement here for multi back to back bulk puts which will be common. I need to understand the result code a little better.

Copy link
Copy Markdown
Contributor

@msirek msirek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @cucaroach and @nvanbenschoten)


pkg/kv/batch.go line 440 at r3 (raw file):

		pr.Value.InitChecksum(k)
		pr.Value.SetBytes(values[keyIdx])
		return pr, len(pr.Value.RawBytes)

It looks like all of the functions passed to bulkRequest share the same code besides the next to last line, so there are only 2 versions. Should these be refactored out into defined functions to pass as parameters? Or, if only the SetBytes or SetTuple line is expected to change, two layers of function calls could be defined. One with the main template, and the a function call parameter that calls either SetBytes or SetTuple.


pkg/kv/batch.go line 1017 at r3 (raw file):

	if reqIdx > 0 {
		reqs = reqs[:reqIdx]
		b.appendReqs(reqs...)

All other calls to appendReqs are immediately followed by a call to initResult. I'm not sure why this is, but I'm wondering if there's a reason for it that applies here too. It looks like the 2 functions don't touch the same data structures, so I guess it's ok to have the order of the calls swapped. Just pointing out the difference in case you want to take a closer look.

Copy link
Copy Markdown
Contributor

@nvb nvb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed all commit messages.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @cucaroach and @msirek)


pkg/kv/batch.go line 435 at r1 (raw file):

Previously, cucaroach (Tommy Reilly) wrote…

I'm not sure what this means. Oh you're saying I can just leave off the RequestHeader yes?

Right. Looks like you made the change.


pkg/kv/batch.go line 436 at r1 (raw file):

Previously, cucaroach (Tommy Reilly) wrote…

I assume we should, is there something I can use to test that the checksums are set and correct?

These calls to InitChecksum need to come after the calls to SetBytes/SetTuple.

To test, you could verify that Value.Verify(key) does not return an error.


pkg/kv/batch.go line 996 at r1 (raw file):

Previously, cucaroach (Tommy Reilly) wrote…

Finishing thought ... I'm unsure where its a good idea to add assertion checks for things that should never happen when Go will generate good enough error messages to clue in future developers who introduce breakages. Sometimes I see checks like this in crdb_test blocks. Curious what your thoughts are.

I think in cases like these where we'd like to place constraints on a function's inputs, doing so explicitly with a helpful message is good. It makes it easier to debug in cases where the function is used incorrectly. It also ensures that bugs don't slip through the cracks. For instance, in these cases, len(keys) > len(values) would have caused a panic, but len(keys) < len(values) would have silently succeeded. If a caller is passing in len(keys) < len(values), we're probably doing them a disservice by silently letting that succeed.


pkg/kv/batch.go line 1007 at r1 (raw file):

Previously, cucaroach (Tommy Reilly) wrote…

So basically we re-use slices across each index and due to partial indexes there are "holes" where we elide KVs that fail the partial index predicate. Basically nil keys is my way of avoiding doing this separate count tracking and compaction at the encoder level and letting it happen here at the KV API boundary where I think its cheaper because we're reformulating everything anyways. Its a little sleazy but I think its kinda the "vector" way, akin to how coldata.Batches utilize selection vectors.

This doesn't feel like the kind of complexity that should be making its way into the KV API, especially if it makes code at the API boundary harder to read, or if it makes the contract of the API more subtle. Given how many times we iterate over the requests in a batch below this level, I'd be pretty surprised if this provided a measurable performance benefit vs. doing the compaction at the encoder level. Also, there's a performance cost to this, which is that we're now sizing b.Results larger than it needs to be in cases where compression is possible. So I'd suggest removing it unless you can demonstrate a performance improvement from the optimization.

@cucaroach cucaroach force-pushed the bulk-put-apis branch 2 times, most recently from 7c27c57 to a7137cb Compare February 12, 2023 20:19
Copy link
Copy Markdown
Contributor Author

@cucaroach cucaroach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ready for another look, thanks!

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @msirek and @nvanbenschoten)


pkg/kv/batch.go line 996 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

I think in cases like these where we'd like to place constraints on a function's inputs, doing so explicitly with a helpful message is good. It makes it easier to debug in cases where the function is used incorrectly. It also ensures that bugs don't slip through the cracks. For instance, in these cases, len(keys) > len(values) would have caused a panic, but len(keys) < len(values) would have silently succeeded. If a caller is passing in len(keys) < len(values), we're probably doing them a disservice by silently letting that succeed.

👍


pkg/kv/batch.go line 1007 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

This doesn't feel like the kind of complexity that should be making its way into the KV API, especially if it makes code at the API boundary harder to read, or if it makes the contract of the API more subtle. Given how many times we iterate over the requests in a batch below this level, I'd be pretty surprised if this provided a measurable performance benefit vs. doing the compaction at the encoder level. Also, there's a performance cost to this, which is that we're now sizing b.Results larger than it needs to be in cases where compression is possible. So I'd suggest removing it unless you can demonstrate a performance improvement from the optimization.

Sounds good, partial indexes are more the exception than the rule I think so no problem to do the compaction for the exceptional case.


pkg/kv/batch.go line 1014 at r1 (raw file):

Previously, cucaroach (Tommy Reilly) wrote…

I do think there's room for improvement here for multi back to back bulk puts which will be common. I need to understand the result code a little better.

Okay I think I figured out the right way to do this.


pkg/kv/batch.go line 1017 at r3 (raw file):

Previously, msirek (Mark Sirek) wrote…

All other calls to appendReqs are immediately followed by a call to initResult. I'm not sure why this is, but I'm wondering if there's a reason for it that applies here too. It looks like the 2 functions don't touch the same data structures, so I guess it's ok to have the order of the calls swapped. Just pointing out the difference in case you want to take a closer look.

Thanks, the request->result mapping is a little funny because of the dynamic number of calls/rows per request but I'm pretty sure the order doesn't matter.

@cucaroach cucaroach requested review from a team as code owners February 14, 2023 23:36
@cucaroach cucaroach requested review from a team February 14, 2023 23:36
Copy link
Copy Markdown
Contributor Author

@cucaroach cucaroach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @msirek and @nvanbenschoten)


pkg/kv/batch.go line 1007 at r1 (raw file):

Previously, cucaroach (Tommy Reilly) wrote…

Okay so I'd like to revisit this. I don't just have empty keys for partial indexes, they also come up with column families where if the value ends up being empty we drop that KV pair. However I reuse the key slices across families, the part of the key up to and including the family ID is saved across families and we just overwrite the rest of the key. If I have to compress the slices I can't do that, so I'd end up having to reallocate the slices of keys which would end up generating a bunch of garbage. Admittedly these extra allocations would only end up hurting those cases but extra memory allocations are one of those hidden costs that end up affecting everything and I'd like to avoid it. What if I allowed empty keys and fixed the extra sizing so we only end up allocating results for the number of real keys? In terms of the batch encoder logic allowing empty keys means much simpler code there for a pretty small complexity hit at the bulk API layer. But the real win for me is the reduction in throw away allocations.

Actually I think we can have a simple clean API AND avoid any copying/throw away allocations if we go with a iterator/generator model instead of mega slices, might come in handy for other things, let me give that a whirl.

@cucaroach cucaroach marked this pull request as draft February 25, 2023 15:26
@cucaroach cucaroach force-pushed the bulk-put-apis branch 2 times, most recently from 07627c6 to 673572a Compare February 25, 2023 21:34
@cucaroach cucaroach marked this pull request as ready for review February 26, 2023 00:36
@cucaroach
Copy link
Copy Markdown
Contributor Author

cucaroach commented Feb 26, 2023

@nvanbenschoten this is ready for another look! Thanks!

Copy link
Copy Markdown
Contributor

@nvb nvb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cucaroach do we have benchmark results that demonstrate the speedup provided by this change?

Reviewed 2 of 2 files at r8, all commit messages.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @cucaroach and @msirek)


pkg/kv/batch.go line 91 at r8 (raw file):

// BulkSourceIterator is the iterator interface for bulk put operations.
type BulkSourceIterator[T GValue] interface {
	Next() (roachpb.Key, T)

What is the contract of this method for when the iterator is exhausted?


pkg/kv/batch.go line 572 at r8 (raw file):

func (b *Batch) CPutTuples(bs BulkSource[[]byte]) {
	numKeys := bs.Len()
	reqs := make([]kvpb.ConditionalPutRequest, numKeys)

Conditional put requests require an expected value. We don't seem to be setting one for any request in CPutTuples or CPutValues.


pkg/kv/batch.go line 1051 at r8 (raw file):

		req, numBytes := requestFactory()
		b.approxMutationReqBytes += numBytes
		newReqs[i].MustSetInner(req)

MustSetInner heap allocates a ResponseUnion_... struct. It's unfortunate that we can't batch allocate all of these structs for the bulk request, but I don't see a good way to support this generically over the request types.


pkg/kv/batch.go line 1062 at r8 (raw file):

		if idx < r.calls {
			if idx < len(r.Rows) {
				return &r, r.Rows[idx], nil

This will cause r (the loop iteration variable) to escape to the heap. I think we want the following instead:

for i := range b.Results {
    r := &b.Results[i]
    ...
    return r, ...
}

Copy link
Copy Markdown
Contributor Author

@cucaroach cucaroach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No but I whipped one up, how's this:

❯❯❯ go test ./pkg/kv -benchmem -run - -bench BenchmarkBulk
goos: darwin
goarch: arm64
pkg: github.com/cockroachdb/cockroach/pkg/kv
BenchmarkBulkBatchAPI/single-10                     3561            358131 ns/op          824200 B/op       5069 allocs/op
BenchmarkBulkBatchAPI/bulk-10                      10000            174356 ns/op          797713 B/op       2008 allocs/op
PASS
ok      github.com/cockroachdb/cockroach/pkg/kv 4.929s

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @msirek and @nvanbenschoten)


pkg/kv/batch.go line 440 at r3 (raw file):

Previously, msirek (Mark Sirek) wrote…

It looks like all of the functions passed to bulkRequest share the same code besides the next to last line, so there are only 2 versions. Should these be refactored out into defined functions to pass as parameters? Or, if only the SetBytes or SetTuple line is expected to change, two layers of function calls could be defined. One with the main template, and the a function call parameter that calls either SetBytes or SetTuple.

They refer to a variable in the surrounding function so I don't think so but I'm open to ideas...


pkg/kv/batch.go line 91 at r8 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

What is the contract of this method for when the iterator is exhausted?

I would say the contract is calling Next more than Len() times is undefined, does that pass muster?


pkg/kv/batch.go line 572 at r8 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Conditional put requests require an expected value. We don't seem to be setting one for any request in CPutTuples or CPutValues.

I was just copying inserter.go which uses insertCPutFn and always passes nil for expValue (well for PK it does, for secondary index it switches to InitPut). Presumably theres a good reason for this and we're going for this behavior: "To conditionally set a value only if the key doesn't currently exist, pass an empty expValue." Maybe I should append "IfEmpty" to CPutValues and CPutTuples? I admit to being confused by the CPut API's menu of expValue, allowNotExist and inline flavors.


pkg/kv/batch.go line 1051 at r8 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

MustSetInner heap allocates a ResponseUnion_... struct. It's unfortunate that we can't batch allocate all of these structs for the bulk request, but I don't see a good way to support this generically over the request types.

Maybe we need first class "bulk" operations so they all live under one Request object but not sure about that.


pkg/kv/batch.go line 1062 at r8 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

This will cause r (the loop iteration variable) to escape to the heap. I think we want the following instead:

for i := range b.Results {
    r := &b.Results[i]
    ...
    return r, ...
}

So the way I have it we heap allocate a kv.Result and copy b.Results[i] into it (00078) and the way you have it a copy is allocated with runtime.convTslice (00063). If I'm reading it right there's an allocation either way. Very annoying, maybe I should just return i and if the caller wants the Result object they can get themselves?

Your way:

# /Users/treilly/vec-encoding/pkg/kv/batch.go
00000 (1058) TEXT github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult(SB), ABIInternal
00001 (1058) FUNCDATA $0, gclocals·bb+LSCCik3x40Cn8eFqL9w==(SB)
00002 (1058) FUNCDATA $1, gclocals·KJo/W9EYQ0eq9CmHhpGqcA==(SB)
00003 (1058) FUNCDATA $2, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.stkobj(SB)
00004 (1058) FUNCDATA $5, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.arginfo1(SB)
00005 (1058) FUNCDATA $6, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.argliveinfo(SB)
b1
00006 (1058) PCDATA $3, $1
v107
00007 (+1060) MOVD 8(R0), R7
v98
00008 (1060) MOVD 16(R0), R8
v139
00009 (1058) MOVD R1, R2
v136
00010 (1058) MOVD $0, R3
b1
00011 (1060) JMP 14
v79
00012 (+1060) ADD $1, R3, R3
v76
00013 (+1069) SUB R10, R1, R1
v134
00014 (+1060) CMP R8, R3
b2
00015 (1060) BGE 45
v106
00016 (+1061) SUB R3<<2, R3, R9
v35
00017 (1061) SUB R9<<5, R7, R9
v40
00018 (+1062) MOVD (R9), R10
v137
00019 (1062) CMP R10, R1
b6
00020 (1062) BGE 12
v73
00021 (+1063) MOVD 24(R9), R7
v38
00022 (1063) MOVD 32(R9), R8
v112
00023 (1063) CMP R8, R1
b9
00024 (1063) BGE 37
b11
00025 (+1064) BHS 84
v28
00026 (+1064) LSL $5, R1, R8
v53
00027 (1064) MOVD (R7)(R8), R8
v61
00028 (1064) ADD R1<<5, R7, R7
v99
00029 (1064) MOVD 8(R7), R2
v74
00030 (1064) MOVD 16(R7), R3
v129
00031 (1064) MOVD 24(R7), R4
v116
00032 (1064) MOVD R9, R0
v124
00033 (1064) MOVD R8, R1
v58
00034 (1064) MOVD $0, R5
v115
00035 (1064) MOVD $0, R6
b13
00036 (1064) RET
v29
00037 (+1066) MOVD R9, R0
v108
00038 (1066) MOVD $0, R1
v95
00039 (1066) MOVD $0, R2
v83
00040 (1066) MOVD R2, R3
v121
00041 (1066) MOVD $0, R4
v122
00042 (1066) MOVD $0, R5
v30
00043 (1066) MOVD R1, R6
b12
00044 (1066) RET
v133
00045 (1058) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv.b(RSP)
v133
00046 (1058) PCDATA $3, $2
v109
00047 (+1071) STP (ZR, ZR), github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-32(RSP)
v84
00048 (1071) STP (ZR, ZR), github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-16(RSP)
v75
00049 (1071) MOVD R2, R0
v88
00050 (1071) PCDATA $1, $1
v88
00051 (1071) CALL runtime.convT64(SB)
v128
00052 (1071) MOVD $type.int(SB), R1
v42
00053 (1071) MOVD R1, github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-32(RSP)
v48
00054 (1071) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-24(RSP)
v141
00055 (1071) MOVD github.com/cockroachdb/cockroach/pkg/kv.b(RSP), R1
v126
00056 (1071) MOVD 8(R1), R0
v123
00057 (1071) MOVD 16(R1), R2
v114
00058 (1071) MOVD 24(R1), R1
v57
00059 (1071) MOVD R1, R3
v27
00060 (1071) MOVD R2, R1
v49
00061 (1071) MOVD R3, R2
v102
00062 (1071) PCDATA $1, $2
v102
00063 (1071) CALL runtime.convTslice(SB)
v45
00064 (1071) MOVD $type.[]github.com/cockroachdb/cockroach/pkg/kv.Result(SB), R1
v140
00065 (1071) MOVD R1, github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-16(RSP)
v43
00066 (1071) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-8(RSP)
v118
00067 (?) NOP
# /Users/treilly/go/pkg/mod/github.com/cockroachdb/errors@v1.9.1/errutil_api.go
v51
00068 (+148) MOVD $1, R0
v41
00069 (148) MOVD $go.string."index %d outside of results: %+v"(SB), R1
v39
00070 (148) MOVD $32, R2
v23
00071 (148) MOVD $github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-32(RSP), R3
v33
00072 (148) MOVD $2, R4
v93
00073 (148) MOVD R4, R5
v120
00074 (+148) PCDATA $1, $3
v120
00075 (+148) CALL github.com/cockroachdb/errors/errutil.AssertionFailedWithDepthf(SB)
# /Users/treilly/vec-encoding/pkg/kv/batch.go
v127
00076 (+1071) MOVD $0, R2
v50
00077 (1071) MOVD R2, R3
v18
00078 (1071) MOVD $0, R4
v100
00079 (1071) MOVD R0, R5
v96
00080 (1071) MOVD R1, R6
v92
00081 (1071) MOVD $0, R0
v69
00082 (1071) MOVD $0, R1
b17
00083 (1071) RET
00084 (1071) PCDATA $1, $-1
00085 (1071) PCDATA $3, $1
v66
00086 (1064) MOVD R1, R0
v55
00087 (1064) MOVD R8, R1
v59
00088 (1064) PCDATA $1, $3
v59
00089 (1064) CALL runtime.panicIndex(SB)
00090 (1064) HINT $0
00091 (?) END

My way:

# /Users/treilly/vec-encoding/pkg/kv/batch.go
00000 (1058) TEXT github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult(SB), ABIInternal
00001 (1058) FUNCDATA $0, gclocals·bb+LSCCik3x40Cn8eFqL9w==(SB)
00002 (1058) FUNCDATA $1, gclocals·s4fpErQgTyW87J+tkvIERg==(SB)
00003 (1058) FUNCDATA $2, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.stkobj(SB)
00004 (1058) FUNCDATA $5, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.arginfo1(SB)
00005 (1058) FUNCDATA $6, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.argliveinfo(SB)
b1
00006 (1058) PCDATA $3, $1
v80
00007 (1058) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv.b(RSP)
v140
00008 (1058) MOVD R1, github.com/cockroachdb/cockroach/pkg/kv.idx+8(RSP)
v140
00009 (1058) PCDATA $3, $-1
v58
00010 (+1060) MOVD $type.github.com/cockroachdb/cockroach/pkg/kv.Result(SB), R0
v17
00011 (1060) PCDATA $1, $0
v17
00012 (1060) CALL runtime.newobject(SB)
v33
00013 (1060) MOVD github.com/cockroachdb/cockroach/pkg/kv.b(RSP), R1
v112
00014 (1060) MOVD 8(R1), R2
v109
00015 (1060) MOVD 16(R1), R3
b1
00016 (1060) CBZ R3, 23
v21
00017 (1060) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv.&r-40(RSP)
v95
00018 (1060) MOVD R3, github.com/cockroachdb/cockroach/pkg/kv..autotmp_29-56(RSP)
v60
00019 (1060) MOVD github.com/cockroachdb/cockroach/pkg/kv.idx+8(RSP), R7
v108
00020 (1058) MOVD R7, R4
v137
00021 (1058) MOVD $0, R5
b3
00022 (1060) JMP 62
v26
00023 (+1070) STP (ZR, ZR), github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-32(RSP)
v86
00024 (1070) STP (ZR, ZR), github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-16(RSP)
v110
00025 (1070) MOVD github.com/cockroachdb/cockroach/pkg/kv.idx+8(RSP), R0
v90
00026 (1070) PCDATA $1, $1
v90
00027 (1070) CALL runtime.convT64(SB)
v97
00028 (1070) MOVD $type.int(SB), R1
v27
00029 (1070) MOVD R1, github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-32(RSP)
v119
00030 (1070) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-24(RSP)
v85
00031 (1070) MOVD github.com/cockroachdb/cockroach/pkg/kv.b(RSP), R1
v138
00032 (1070) MOVD 8(R1), R0
v143
00033 (1070) MOVD 16(R1), R2
v133
00034 (1070) MOVD 24(R1), R1
v136
00035 (1070) MOVD R1, R3
v24
00036 (1070) MOVD R2, R1
v64
00037 (1070) MOVD R3, R2
v104
00038 (1070) PCDATA $1, $2
v104
00039 (1070) CALL runtime.convTslice(SB)
v117
00040 (1070) MOVD $type.[]github.com/cockroachdb/cockroach/pkg/kv.Result(SB), R1
v44
00041 (1070) MOVD R1, github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-16(RSP)
v79
00042 (1070) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-8(RSP)
v120
00043 (?) NOP
# /Users/treilly/go/pkg/mod/github.com/cockroachdb/errors@v1.9.1/errutil_api.go
v130
00044 (+148) MOVD $1, R0
v134
00045 (148) MOVD $go.string."index %d outside of results: %+v"(SB), R1
v141
00046 (148) MOVD $32, R2
v52
00047 (148) MOVD $github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-32(RSP), R3
v69
00048 (148) MOVD $2, R4
v45
00049 (148) MOVD R4, R5
v122
00050 (+148) PCDATA $1, $3
v122
00051 (+148) CALL github.com/cockroachdb/errors/errutil.AssertionFailedWithDepthf(SB)
# /Users/treilly/vec-encoding/pkg/kv/batch.go
v40
00052 (+1070) MOVD $0, R2
v98
00053 (1070) MOVD R2, R3
v75
00054 (1070) MOVD $0, R4
v102
00055 (1070) MOVD R0, R5
v126
00056 (1070) MOVD R1, R6
v36
00057 (1070) MOVD $0, R0
v101
00058 (1070) MOVD $0, R1
b17
00059 (1070) RET
v81
00060 (1060) ADD $96, R2, R2
v135
00061 (1060) MOVD R10, R5
v50
00062 (1060) PCDATA $0, $-2
v50
00063 (+1060) MOVD $runtime.writeBarrier(SB), R8
v78
00064 (1060) MOVWU (R8), R9
b5
00065 (1060) CBNZW R9, 74
v43
00066 (+1060) ADD $88, R2, R9
v99
00067 (1060) MOVD R0, R17
v100
00068 (1060) MOVD R2, R16
v111
00069 (1060) MOVD.P 8(R16), R27
v111
00070 (1060) MOVD.P R27, 8(R17)
v111
00071 (1060) CMP R9, R16
v111
00072 (1060) BLE 69
b16
00073 (1060) JMP 88
v32
00074 (1060) MOVD R5, github.com/cockroachdb/cockroach/pkg/kv..autotmp_30-64(RSP)
v51
00075 (1060) MOVD R2, github.com/cockroachdb/cockroach/pkg/kv..autotmp_31-48(RSP)
v42
00076 (1061) MOVD R7, github.com/cockroachdb/cockroach/pkg/kv..autotmp_32-72(RSP)
v28
00077 (+1060) MOVD R0, R1
v129
00078 (1060) MOVD $type.github.com/cockroachdb/cockroach/pkg/kv.Result(SB), R0
v123
00079 (+1060) CALL runtime.typedmemmove(SB)
v132
00080 (1061) MOVD github.com/cockroachdb/cockroach/pkg/kv.&r-40(RSP), R0
v68
00081 (1070) MOVD github.com/cockroachdb/cockroach/pkg/kv.b(RSP), R1
v66
00082 (1060) MOVD github.com/cockroachdb/cockroach/pkg/kv..autotmp_31-48(RSP), R2
v65
00083 (1060) MOVD github.com/cockroachdb/cockroach/pkg/kv..autotmp_29-56(RSP), R3
v74
00084 (1070) MOVD github.com/cockroachdb/cockroach/pkg/kv.idx+8(RSP), R4
v71
00085 (1060) MOVD github.com/cockroachdb/cockroach/pkg/kv..autotmp_30-64(RSP), R5
v77
00086 (1061) MOVD github.com/cockroachdb/cockroach/pkg/kv..autotmp_32-72(RSP), R7
v76
00087 (1060) MOVD $runtime.writeBarrier(SB), R8
v37
00088 (+1061) PCDATA $0, $-1
v37
00089 (+1061) MOVD (R0), R9
v55
00090 (1061) CMP R9, R7
b15
00091 (1061) BLT 97
v73
00092 (+1060) ADD $1, R5, R10
v70
00093 (+1068) SUB R9, R7, R7
v67
00094 (1060) CMP R10, R3
b6
00095 (1060) BGT 60
b6
00096 (1060) JMP 23
v49
00097 (+1062) MOVD 24(R0), R8
v47
00098 (1062) MOVD 32(R0), R1
v94
00099 (1062) CMP R1, R7
b9
00100 (1062) BGE 112
b11
00101 (+1063) PCDATA $1, $-1
b11
00102 (+1063) BHS 119
v144
00103 (+1063) LSL $5, R7, R9
v128
00104 (1063) MOVD (R8)(R9), R1
v56
00105 (1063) ADD R7<<5, R8, R7
v125
00106 (1063) MOVD 8(R7), R2
v116
00107 (1063) MOVD 16(R7), R3
v131
00108 (1063) MOVD 24(R7), R4
v22
00109 (1063) MOVD $0, R5
v82
00110 (1063) MOVD $0, R6
b13
00111 (1063) RET
v62
00112 (+1065) MOVD $0, R1
v15
00113 (1065) MOVD $0, R2
v13
00114 (1065) MOVD R2, R3
v10
00115 (1065) MOVD $0, R4
v39
00116 (1065) MOVD $0, R5
v142
00117 (1065) MOVD R1, R6
b12
00118 (1065) RET
v139
00119 (1063) MOVD R7, R0
v54
00120 (1063) PCDATA $1, $3
v54
00121 (1063) CALL runtime.panicIndex(SB)
00122 (1063) HINT $0
00123 (?) END

Copy link
Copy Markdown
Contributor Author

@cucaroach cucaroach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @msirek and @nvanbenschoten)


pkg/kv/batch.go line 1062 at r8 (raw file):

Previously, cucaroach (Tommy Reilly) wrote…

So the way I have it we heap allocate a kv.Result and copy b.Results[i] into it (00078) and the way you have it a copy is allocated with runtime.convTslice (00063). If I'm reading it right there's an allocation either way. Very annoying, maybe I should just return i and if the caller wants the Result object they can get themselves?

Your way:

# /Users/treilly/vec-encoding/pkg/kv/batch.go
00000 (1058) TEXT github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult(SB), ABIInternal
00001 (1058) FUNCDATA $0, gclocals·bb+LSCCik3x40Cn8eFqL9w==(SB)
00002 (1058) FUNCDATA $1, gclocals·KJo/W9EYQ0eq9CmHhpGqcA==(SB)
00003 (1058) FUNCDATA $2, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.stkobj(SB)
00004 (1058) FUNCDATA $5, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.arginfo1(SB)
00005 (1058) FUNCDATA $6, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.argliveinfo(SB)
b1
00006 (1058) PCDATA $3, $1
v107
00007 (+1060) MOVD 8(R0), R7
v98
00008 (1060) MOVD 16(R0), R8
v139
00009 (1058) MOVD R1, R2
v136
00010 (1058) MOVD $0, R3
b1
00011 (1060) JMP 14
v79
00012 (+1060) ADD $1, R3, R3
v76
00013 (+1069) SUB R10, R1, R1
v134
00014 (+1060) CMP R8, R3
b2
00015 (1060) BGE 45
v106
00016 (+1061) SUB R3<<2, R3, R9
v35
00017 (1061) SUB R9<<5, R7, R9
v40
00018 (+1062) MOVD (R9), R10
v137
00019 (1062) CMP R10, R1
b6
00020 (1062) BGE 12
v73
00021 (+1063) MOVD 24(R9), R7
v38
00022 (1063) MOVD 32(R9), R8
v112
00023 (1063) CMP R8, R1
b9
00024 (1063) BGE 37
b11
00025 (+1064) BHS 84
v28
00026 (+1064) LSL $5, R1, R8
v53
00027 (1064) MOVD (R7)(R8), R8
v61
00028 (1064) ADD R1<<5, R7, R7
v99
00029 (1064) MOVD 8(R7), R2
v74
00030 (1064) MOVD 16(R7), R3
v129
00031 (1064) MOVD 24(R7), R4
v116
00032 (1064) MOVD R9, R0
v124
00033 (1064) MOVD R8, R1
v58
00034 (1064) MOVD $0, R5
v115
00035 (1064) MOVD $0, R6
b13
00036 (1064) RET
v29
00037 (+1066) MOVD R9, R0
v108
00038 (1066) MOVD $0, R1
v95
00039 (1066) MOVD $0, R2
v83
00040 (1066) MOVD R2, R3
v121
00041 (1066) MOVD $0, R4
v122
00042 (1066) MOVD $0, R5
v30
00043 (1066) MOVD R1, R6
b12
00044 (1066) RET
v133
00045 (1058) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv.b(RSP)
v133
00046 (1058) PCDATA $3, $2
v109
00047 (+1071) STP (ZR, ZR), github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-32(RSP)
v84
00048 (1071) STP (ZR, ZR), github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-16(RSP)
v75
00049 (1071) MOVD R2, R0
v88
00050 (1071) PCDATA $1, $1
v88
00051 (1071) CALL runtime.convT64(SB)
v128
00052 (1071) MOVD $type.int(SB), R1
v42
00053 (1071) MOVD R1, github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-32(RSP)
v48
00054 (1071) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-24(RSP)
v141
00055 (1071) MOVD github.com/cockroachdb/cockroach/pkg/kv.b(RSP), R1
v126
00056 (1071) MOVD 8(R1), R0
v123
00057 (1071) MOVD 16(R1), R2
v114
00058 (1071) MOVD 24(R1), R1
v57
00059 (1071) MOVD R1, R3
v27
00060 (1071) MOVD R2, R1
v49
00061 (1071) MOVD R3, R2
v102
00062 (1071) PCDATA $1, $2
v102
00063 (1071) CALL runtime.convTslice(SB)
v45
00064 (1071) MOVD $type.[]github.com/cockroachdb/cockroach/pkg/kv.Result(SB), R1
v140
00065 (1071) MOVD R1, github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-16(RSP)
v43
00066 (1071) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-8(RSP)
v118
00067 (?) NOP
# /Users/treilly/go/pkg/mod/github.com/cockroachdb/errors@v1.9.1/errutil_api.go
v51
00068 (+148) MOVD $1, R0
v41
00069 (148) MOVD $go.string."index %d outside of results: %+v"(SB), R1
v39
00070 (148) MOVD $32, R2
v23
00071 (148) MOVD $github.com/cockroachdb/cockroach/pkg/kv..autotmp_16-32(RSP), R3
v33
00072 (148) MOVD $2, R4
v93
00073 (148) MOVD R4, R5
v120
00074 (+148) PCDATA $1, $3
v120
00075 (+148) CALL github.com/cockroachdb/errors/errutil.AssertionFailedWithDepthf(SB)
# /Users/treilly/vec-encoding/pkg/kv/batch.go
v127
00076 (+1071) MOVD $0, R2
v50
00077 (1071) MOVD R2, R3
v18
00078 (1071) MOVD $0, R4
v100
00079 (1071) MOVD R0, R5
v96
00080 (1071) MOVD R1, R6
v92
00081 (1071) MOVD $0, R0
v69
00082 (1071) MOVD $0, R1
b17
00083 (1071) RET
00084 (1071) PCDATA $1, $-1
00085 (1071) PCDATA $3, $1
v66
00086 (1064) MOVD R1, R0
v55
00087 (1064) MOVD R8, R1
v59
00088 (1064) PCDATA $1, $3
v59
00089 (1064) CALL runtime.panicIndex(SB)
00090 (1064) HINT $0
00091 (?) END

My way:

# /Users/treilly/vec-encoding/pkg/kv/batch.go
00000 (1058) TEXT github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult(SB), ABIInternal
00001 (1058) FUNCDATA $0, gclocals·bb+LSCCik3x40Cn8eFqL9w==(SB)
00002 (1058) FUNCDATA $1, gclocals·s4fpErQgTyW87J+tkvIERg==(SB)
00003 (1058) FUNCDATA $2, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.stkobj(SB)
00004 (1058) FUNCDATA $5, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.arginfo1(SB)
00005 (1058) FUNCDATA $6, github.com/cockroachdb/cockroach/pkg/kv.(*Batch).GetResult.argliveinfo(SB)
b1
00006 (1058) PCDATA $3, $1
v80
00007 (1058) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv.b(RSP)
v140
00008 (1058) MOVD R1, github.com/cockroachdb/cockroach/pkg/kv.idx+8(RSP)
v140
00009 (1058) PCDATA $3, $-1
v58
00010 (+1060) MOVD $type.github.com/cockroachdb/cockroach/pkg/kv.Result(SB), R0
v17
00011 (1060) PCDATA $1, $0
v17
00012 (1060) CALL runtime.newobject(SB)
v33
00013 (1060) MOVD github.com/cockroachdb/cockroach/pkg/kv.b(RSP), R1
v112
00014 (1060) MOVD 8(R1), R2
v109
00015 (1060) MOVD 16(R1), R3
b1
00016 (1060) CBZ R3, 23
v21
00017 (1060) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv.&r-40(RSP)
v95
00018 (1060) MOVD R3, github.com/cockroachdb/cockroach/pkg/kv..autotmp_29-56(RSP)
v60
00019 (1060) MOVD github.com/cockroachdb/cockroach/pkg/kv.idx+8(RSP), R7
v108
00020 (1058) MOVD R7, R4
v137
00021 (1058) MOVD $0, R5
b3
00022 (1060) JMP 62
v26
00023 (+1070) STP (ZR, ZR), github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-32(RSP)
v86
00024 (1070) STP (ZR, ZR), github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-16(RSP)
v110
00025 (1070) MOVD github.com/cockroachdb/cockroach/pkg/kv.idx+8(RSP), R0
v90
00026 (1070) PCDATA $1, $1
v90
00027 (1070) CALL runtime.convT64(SB)
v97
00028 (1070) MOVD $type.int(SB), R1
v27
00029 (1070) MOVD R1, github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-32(RSP)
v119
00030 (1070) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-24(RSP)
v85
00031 (1070) MOVD github.com/cockroachdb/cockroach/pkg/kv.b(RSP), R1
v138
00032 (1070) MOVD 8(R1), R0
v143
00033 (1070) MOVD 16(R1), R2
v133
00034 (1070) MOVD 24(R1), R1
v136
00035 (1070) MOVD R1, R3
v24
00036 (1070) MOVD R2, R1
v64
00037 (1070) MOVD R3, R2
v104
00038 (1070) PCDATA $1, $2
v104
00039 (1070) CALL runtime.convTslice(SB)
v117
00040 (1070) MOVD $type.[]github.com/cockroachdb/cockroach/pkg/kv.Result(SB), R1
v44
00041 (1070) MOVD R1, github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-16(RSP)
v79
00042 (1070) MOVD R0, github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-8(RSP)
v120
00043 (?) NOP
# /Users/treilly/go/pkg/mod/github.com/cockroachdb/errors@v1.9.1/errutil_api.go
v130
00044 (+148) MOVD $1, R0
v134
00045 (148) MOVD $go.string."index %d outside of results: %+v"(SB), R1
v141
00046 (148) MOVD $32, R2
v52
00047 (148) MOVD $github.com/cockroachdb/cockroach/pkg/kv..autotmp_17-32(RSP), R3
v69
00048 (148) MOVD $2, R4
v45
00049 (148) MOVD R4, R5
v122
00050 (+148) PCDATA $1, $3
v122
00051 (+148) CALL github.com/cockroachdb/errors/errutil.AssertionFailedWithDepthf(SB)
# /Users/treilly/vec-encoding/pkg/kv/batch.go
v40
00052 (+1070) MOVD $0, R2
v98
00053 (1070) MOVD R2, R3
v75
00054 (1070) MOVD $0, R4
v102
00055 (1070) MOVD R0, R5
v126
00056 (1070) MOVD R1, R6
v36
00057 (1070) MOVD $0, R0
v101
00058 (1070) MOVD $0, R1
b17
00059 (1070) RET
v81
00060 (1060) ADD $96, R2, R2
v135
00061 (1060) MOVD R10, R5
v50
00062 (1060) PCDATA $0, $-2
v50
00063 (+1060) MOVD $runtime.writeBarrier(SB), R8
v78
00064 (1060) MOVWU (R8), R9
b5
00065 (1060) CBNZW R9, 74
v43
00066 (+1060) ADD $88, R2, R9
v99
00067 (1060) MOVD R0, R17
v100
00068 (1060) MOVD R2, R16
v111
00069 (1060) MOVD.P 8(R16), R27
v111
00070 (1060) MOVD.P R27, 8(R17)
v111
00071 (1060) CMP R9, R16
v111
00072 (1060) BLE 69
b16
00073 (1060) JMP 88
v32
00074 (1060) MOVD R5, github.com/cockroachdb/cockroach/pkg/kv..autotmp_30-64(RSP)
v51
00075 (1060) MOVD R2, github.com/cockroachdb/cockroach/pkg/kv..autotmp_31-48(RSP)
v42
00076 (1061) MOVD R7, github.com/cockroachdb/cockroach/pkg/kv..autotmp_32-72(RSP)
v28
00077 (+1060) MOVD R0, R1
v129
00078 (1060) MOVD $type.github.com/cockroachdb/cockroach/pkg/kv.Result(SB), R0
v123
00079 (+1060) CALL runtime.typedmemmove(SB)
v132
00080 (1061) MOVD github.com/cockroachdb/cockroach/pkg/kv.&r-40(RSP), R0
v68
00081 (1070) MOVD github.com/cockroachdb/cockroach/pkg/kv.b(RSP), R1
v66
00082 (1060) MOVD github.com/cockroachdb/cockroach/pkg/kv..autotmp_31-48(RSP), R2
v65
00083 (1060) MOVD github.com/cockroachdb/cockroach/pkg/kv..autotmp_29-56(RSP), R3
v74
00084 (1070) MOVD github.com/cockroachdb/cockroach/pkg/kv.idx+8(RSP), R4
v71
00085 (1060) MOVD github.com/cockroachdb/cockroach/pkg/kv..autotmp_30-64(RSP), R5
v77
00086 (1061) MOVD github.com/cockroachdb/cockroach/pkg/kv..autotmp_32-72(RSP), R7
v76
00087 (1060) MOVD $runtime.writeBarrier(SB), R8
v37
00088 (+1061) PCDATA $0, $-1
v37
00089 (+1061) MOVD (R0), R9
v55
00090 (1061) CMP R9, R7
b15
00091 (1061) BLT 97
v73
00092 (+1060) ADD $1, R5, R10
v70
00093 (+1068) SUB R9, R7, R7
v67
00094 (1060) CMP R10, R3
b6
00095 (1060) BGT 60
b6
00096 (1060) JMP 23
v49
00097 (+1062) MOVD 24(R0), R8
v47
00098 (1062) MOVD 32(R0), R1
v94
00099 (1062) CMP R1, R7
b9
00100 (1062) BGE 112
b11
00101 (+1063) PCDATA $1, $-1
b11
00102 (+1063) BHS 119
v144
00103 (+1063) LSL $5, R7, R9
v128
00104 (1063) MOVD (R8)(R9), R1
v56
00105 (1063) ADD R7<<5, R8, R7
v125
00106 (1063) MOVD 8(R7), R2
v116
00107 (1063) MOVD 16(R7), R3
v131
00108 (1063) MOVD 24(R7), R4
v22
00109 (1063) MOVD $0, R5
v82
00110 (1063) MOVD $0, R6
b13
00111 (1063) RET
v62
00112 (+1065) MOVD $0, R1
v15
00113 (1065) MOVD $0, R2
v13
00114 (1065) MOVD R2, R3
v10
00115 (1065) MOVD $0, R4
v39
00116 (1065) MOVD $0, R5
v142
00117 (1065) MOVD R1, R6
b12
00118 (1065) RET
v139
00119 (1063) MOVD R7, R0
v54
00120 (1063) PCDATA $1, $3
v54
00121 (1063) CALL runtime.panicIndex(SB)
00122 (1063) HINT $0
00123 (?) END

Nevermind, you're right, the convTslice allocation in your way is for the error path argument to AssertionFailedF.

@cucaroach cucaroach force-pushed the bulk-put-apis branch 2 times, most recently from 9626573 to 0de779e Compare March 1, 2023 02:43
Copy link
Copy Markdown
Contributor

@nvb nvb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No but I whipped one up, how's this:

Sorry, I meant do you have benchmarks that demonstrate that this new API extension can be used to provide a meaningful speedup for its expected use cases?

On that topic, what are the expected use cases where we'll use this API?

Reviewed 1 of 2 files at r9.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @cucaroach and @msirek)


pkg/kv/batch.go line 91 at r8 (raw file):

Previously, cucaroach (Tommy Reilly) wrote…

I would say the contract is calling Next more than Len() times is undefined, does that pass muster?

It seems fine, though maybe better to say that it will panic. Up to you.


pkg/kv/batch.go line 1051 at r8 (raw file):

Previously, cucaroach (Tommy Reilly) wrote…

Maybe we need first class "bulk" operations so they all live under one Request object but not sure about that.

This realization and the question above about benchmarking are giving me pause about whether introducing new semi-typed, semi-specialized APIs on the Batch object is the right path, vs. using the lower-level BatchRequest API and txn.Send directly like we do in txnKVFetcher.fetch. It sounds like this new API improves perf in some areas but also leaves some on the table. Switching to the BatchRequest API would give us full control over memory allocations to facilitate batching and re-use, and it also avoids unnecessary wrapping on the response path. If we're saying that the inserter.go logic is so performance critical that it can no longer tolerate the overhead of KV's well-typed API (it's good that we're getting to this point!), should we first evaluate the approach of using its existing raw API?

Copy link
Copy Markdown
Contributor Author

@cucaroach cucaroach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the closest thing I have is the BuildFromDatum and BuildFromCol rows here:

https://docs.google.com/spreadsheets/d/10mayXq3ICsRD__UuacT1UFT5I0I7anWzrNjNjqqFEvc/edit#gid=0

BuildFromDatum measures the speed of building the kv.Batch from datums row by row and BuildFromCol builds them from a coldata.Batch. I can't tease out how much is due to datum overhead vs the new vectorized bulk encoder vs using the bulk APIs w/o further experiments but I can do that if you'd like, I suspect the majority of the speedup comes from the new bulk encoder. I do know that we've seen surprising speedups from removing allocations so I suspect going back to the individual CPut/InitPut calls would definitely have a measurable affect and drive a lot more GC activity.

The expected use cases are COPY today, prepared batch inserts tomorrow and in the future maybe other types of mutations.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @msirek and @nvanbenschoten)


pkg/kv/batch.go line 1051 at r8 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

This realization and the question above about benchmarking are giving me pause about whether introducing new semi-typed, semi-specialized APIs on the Batch object is the right path, vs. using the lower-level BatchRequest API and txn.Send directly like we do in txnKVFetcher.fetch. It sounds like this new API improves perf in some areas but also leaves some on the table. Switching to the BatchRequest API would give us full control over memory allocations to facilitate batching and re-use, and it also avoids unnecessary wrapping on the response path. If we're saying that the inserter.go logic is so performance critical that it can no longer tolerate the overhead of KV's well-typed API (it's good that we're getting to this point!), should we first evaluate the approach of using its existing raw API?

Well I think having high level first class support for batch mutations is a good thing but I also agree what's the point if the API is wonky and still has in-efficiencies. I'm also intrigued by the this BatchRequest idea and hadn't considered it before. Although I feel like I could get rid of the MustSetInner cost by allocating a slice of request/union pair structs like the txnKVFetcher does. Let me give that a whirl.

What does "unnecessary wrapping on the response path" mean?

@cucaroach
Copy link
Copy Markdown
Contributor Author

cucaroach commented Mar 1, 2023

Okay that went well, I got rid of the per key result allocation (which should have died when I figured out the calls/numRows machinery) and I got the unions bulk allocated too ala txnKVFetcher. Let me know what you think, thanks for pushing for polish on this!

Latest benchmark results:

BenchmarkBulkBatchAPI
BenchmarkBulkBatchAPI/single
BenchmarkBulkBatchAPI/single-10                     3373            501108 ns/op          858203 B/op       5073 allocs/op
BenchmarkBulkBatchAPI/bulk
BenchmarkBulkBatchAPI/bulk-10                      17415             75131 ns/op          225997 B/op       1006 allocs/op
PASS

@cucaroach
Copy link
Copy Markdown
Contributor Author

Another thought that occurred to me is that we only really need the bulkRequest function to live in Batch, we could make it public and move all the ergonomic wrappers around it to the vector encoding package. Would that be better for now?

Copy link
Copy Markdown
Contributor

@nvb nvb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 1 of 2 files at r9, 1 of 1 files at r11, all commit messages.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @cucaroach and @msirek)


pkg/kv/batch.go line 614 at r11 (raw file):

		union kvpb.RequestUnion_ConditionalPut
	}, numKeys)

nit: stray line.

These are simple analogs to existing APIs that do all the memory
allocations in bulk.

Epic: CRDB-18892
Informs: cockroachdb#91831
Release note: None
@cucaroach
Copy link
Copy Markdown
Contributor Author

bors r=nvanbenschoten
TFTRs!

@craig
Copy link
Copy Markdown
Contributor

craig bot commented Mar 2, 2023

Build failed:

@cucaroach
Copy link
Copy Markdown
Contributor Author

bors retry

@craig
Copy link
Copy Markdown
Contributor

craig bot commented Mar 2, 2023

Build succeeded:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants