Skip to content

using Sprintf consumes lots of CPU #30274

Closed
@llkhacquan

Description

@llkhacquan

Rationale

Why should this feature exist?

image

As we can see from the cpu profiling. Most cpu time (*TypedData).HashStruct spent on is about isPrimitiveTypeValid, which is very slow because it use fmt.Sprintf to do some simple formatting (see the following code)

This is the copied code from v1.14.6.

// github.com/ethereum/[email protected]/signer/core/apitypes/types.go:845
// Checks if the primitive value is valid
func isPrimitiveTypeValid(primitiveType string) bool {
	if primitiveType == "address" ||
		primitiveType == "address[]" ||
		primitiveType == "bool" ||
		primitiveType == "bool[]" ||
		primitiveType == "string" ||
		primitiveType == "string[]" ||
		primitiveType == "bytes" ||
		primitiveType == "bytes[]" ||
		primitiveType == "int" ||
		primitiveType == "int[]" ||
		primitiveType == "uint" ||
		primitiveType == "uint[]" {
		return true
	}
	// For 'bytesN', 'bytesN[]', we allow N from 1 to 32
	for n := 1; n <= 32; n++ {
		// e.g. 'bytes28' or 'bytes28[]'
		if primitiveType == fmt.Sprintf("bytes%d", n) || primitiveType == fmt.Sprintf("bytes%d[]", n) {
			return true
		}
	}
	// For 'intN','intN[]' and 'uintN','uintN[]' we allow N in increments of 8, from 8 up to 256
	for n := 8; n <= 256; n += 8 {
		if primitiveType == fmt.Sprintf("int%d", n) || primitiveType == fmt.Sprintf("int%d[]", n) {
			return true
		}
		if primitiveType == fmt.Sprintf("uint%d", n) || primitiveType == fmt.Sprintf("uint%d[]", n) {
			return true
		}
	}
	return false
}

What are the use-cases?

HashStruct is used to verify EIP712 signature. It would be super nice if it's fast.

Implementation

Do you have ideas regarding the implementation of this feature?

We need to reduce call to fmt.Sprintf, some ideas:

  • precompute all possible value of primitiveType (best performance I guess)
  • replace fmt.Sprintf with strconv.Itoa. Example: fmt.Sprintf("ints%d, n) => "ints" + strconv.Itoa(n) (trivial fix)

Are you willing to implement this feature?

Yes.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions