mirror of
https://github.com/aykhans/sarin.git
synced 2026-04-14 20:19:37 +00:00
perf: reduce memory allocations in request generator
This commit is contained in:
@@ -43,19 +43,34 @@ func NewRequestGenerator(
|
|||||||
randSource := NewDefaultRandSource()
|
randSource := NewDefaultRandSource()
|
||||||
//nolint:gosec // G404: Using non-cryptographic rand for load testing, not security
|
//nolint:gosec // G404: Using non-cryptographic rand for load testing, not security
|
||||||
localRand := rand.New(randSource)
|
localRand := rand.New(randSource)
|
||||||
templateFuncMap := NewDefaultTemplateFuncMap(randSource, fileCache)
|
|
||||||
|
|
||||||
pathGenerator, isPathGeneratorDynamic := createTemplateFunc(requestURL.Path, templateFuncMap)
|
// Funcs() is only called if a value actually contains template syntax.
|
||||||
methodGenerator, isMethodGeneratorDynamic := NewMethodGeneratorFunc(localRand, methods, templateFuncMap)
|
// The root template is shared across all createTemplateFunc calls so Funcs() is called at most once.
|
||||||
paramsGenerator, isParamsGeneratorDynamic := NewParamsGeneratorFunc(localRand, params, templateFuncMap)
|
var templateRoot *template.Template
|
||||||
headersGenerator, isHeadersGeneratorDynamic := NewHeadersGeneratorFunc(localRand, headers, templateFuncMap)
|
lazyTemplateRoot := func() *template.Template {
|
||||||
cookiesGenerator, isCookiesGeneratorDynamic := NewCookiesGeneratorFunc(localRand, cookies, templateFuncMap)
|
if templateRoot == nil {
|
||||||
|
templateRoot = template.New("").Funcs(NewDefaultTemplateFuncMap(randSource, fileCache))
|
||||||
|
}
|
||||||
|
return templateRoot
|
||||||
|
}
|
||||||
|
|
||||||
|
pathGenerator, isPathGeneratorDynamic := createTemplateFunc(requestURL.Path, lazyTemplateRoot)
|
||||||
|
methodGenerator, isMethodGeneratorDynamic := NewMethodGeneratorFunc(localRand, methods, lazyTemplateRoot)
|
||||||
|
paramsGenerator, isParamsGeneratorDynamic := NewParamsGeneratorFunc(localRand, params, lazyTemplateRoot)
|
||||||
|
headersGenerator, isHeadersGeneratorDynamic := NewHeadersGeneratorFunc(localRand, headers, lazyTemplateRoot)
|
||||||
|
cookiesGenerator, isCookiesGeneratorDynamic := NewCookiesGeneratorFunc(localRand, cookies, lazyTemplateRoot)
|
||||||
|
|
||||||
bodyTemplateFuncMapData := &BodyTemplateFuncMapData{}
|
bodyTemplateFuncMapData := &BodyTemplateFuncMapData{}
|
||||||
bodyTemplateFuncMap := NewDefaultBodyTemplateFuncMap(randSource, bodyTemplateFuncMapData, fileCache)
|
var bodyTemplateRoot *template.Template
|
||||||
bodyGenerator, isBodyGeneratorDynamic := NewBodyGeneratorFunc(localRand, bodies, bodyTemplateFuncMap)
|
lazyBodyTemplateRoot := func() *template.Template {
|
||||||
|
if bodyTemplateRoot == nil {
|
||||||
|
bodyTemplateRoot = template.New("").Funcs(NewDefaultBodyTemplateFuncMap(randSource, bodyTemplateFuncMapData, fileCache))
|
||||||
|
}
|
||||||
|
return bodyTemplateRoot
|
||||||
|
}
|
||||||
|
bodyGenerator, isBodyGeneratorDynamic := NewBodyGeneratorFunc(localRand, bodies, lazyBodyTemplateRoot)
|
||||||
|
|
||||||
valuesGenerator := NewValuesGeneratorFunc(values, templateFuncMap)
|
valuesGenerator := NewValuesGeneratorFunc(values, lazyTemplateRoot)
|
||||||
|
|
||||||
hasScripts := scriptTransformer != nil && !scriptTransformer.IsEmpty()
|
hasScripts := scriptTransformer != nil && !scriptTransformer.IsEmpty()
|
||||||
|
|
||||||
@@ -170,8 +185,8 @@ func applyRequestDataToFastHTTP(reqData *script.RequestData, req *fasthttp.Reque
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMethodGeneratorFunc(localRand *rand.Rand, methods []string, templateFunctions template.FuncMap) (requestDataGenerator, bool) {
|
func NewMethodGeneratorFunc(localRand *rand.Rand, methods []string, lazyRoot func() *template.Template) (requestDataGenerator, bool) {
|
||||||
methodGenerator, isDynamic := buildStringSliceGenerator(localRand, methods, templateFunctions)
|
methodGenerator, isDynamic := buildStringSliceGenerator(localRand, methods, lazyRoot)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
method string
|
method string
|
||||||
@@ -188,8 +203,8 @@ func NewMethodGeneratorFunc(localRand *rand.Rand, methods []string, templateFunc
|
|||||||
}, isDynamic
|
}, isDynamic
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBodyGeneratorFunc(localRand *rand.Rand, bodies []string, templateFunctions template.FuncMap) (requestDataGenerator, bool) {
|
func NewBodyGeneratorFunc(localRand *rand.Rand, bodies []string, lazyRoot func() *template.Template) (requestDataGenerator, bool) {
|
||||||
bodyGenerator, isDynamic := buildStringSliceGenerator(localRand, bodies, templateFunctions)
|
bodyGenerator, isDynamic := buildStringSliceGenerator(localRand, bodies, lazyRoot)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
body string
|
body string
|
||||||
@@ -206,8 +221,8 @@ func NewBodyGeneratorFunc(localRand *rand.Rand, bodies []string, templateFunctio
|
|||||||
}, isDynamic
|
}, isDynamic
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewParamsGeneratorFunc(localRand *rand.Rand, params types.Params, templateFunctions template.FuncMap) (requestDataGenerator, bool) {
|
func NewParamsGeneratorFunc(localRand *rand.Rand, params types.Params, lazyRoot func() *template.Template) (requestDataGenerator, bool) {
|
||||||
generators, isDynamic := buildKeyValueGenerators(localRand, params, templateFunctions)
|
generators, isDynamic := buildKeyValueGenerators(localRand, params, lazyRoot)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
key, value string
|
key, value string
|
||||||
@@ -231,8 +246,8 @@ func NewParamsGeneratorFunc(localRand *rand.Rand, params types.Params, templateF
|
|||||||
}, isDynamic
|
}, isDynamic
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHeadersGeneratorFunc(localRand *rand.Rand, headers types.Headers, templateFunctions template.FuncMap) (requestDataGenerator, bool) {
|
func NewHeadersGeneratorFunc(localRand *rand.Rand, headers types.Headers, lazyRoot func() *template.Template) (requestDataGenerator, bool) {
|
||||||
generators, isDynamic := buildKeyValueGenerators(localRand, headers, templateFunctions)
|
generators, isDynamic := buildKeyValueGenerators(localRand, headers, lazyRoot)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
key, value string
|
key, value string
|
||||||
@@ -256,8 +271,8 @@ func NewHeadersGeneratorFunc(localRand *rand.Rand, headers types.Headers, templa
|
|||||||
}, isDynamic
|
}, isDynamic
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCookiesGeneratorFunc(localRand *rand.Rand, cookies types.Cookies, templateFunctions template.FuncMap) (requestDataGenerator, bool) {
|
func NewCookiesGeneratorFunc(localRand *rand.Rand, cookies types.Cookies, lazyRoot func() *template.Template) (requestDataGenerator, bool) {
|
||||||
generators, isDynamic := buildKeyValueGenerators(localRand, cookies, templateFunctions)
|
generators, isDynamic := buildKeyValueGenerators(localRand, cookies, lazyRoot)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
key, value string
|
key, value string
|
||||||
@@ -281,11 +296,11 @@ func NewCookiesGeneratorFunc(localRand *rand.Rand, cookies types.Cookies, templa
|
|||||||
}, isDynamic
|
}, isDynamic
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewValuesGeneratorFunc(values []string, templateFunctions template.FuncMap) func() (valuesData, error) {
|
func NewValuesGeneratorFunc(values []string, lazyRoot func() *template.Template) func() (valuesData, error) {
|
||||||
generators := make([]func(_ any) (string, error), len(values))
|
generators := make([]func(_ any) (string, error), len(values))
|
||||||
|
|
||||||
for i, v := range values {
|
for i, v := range values {
|
||||||
generators[i], _ = createTemplateFunc(v, templateFunctions)
|
generators[i], _ = createTemplateFunc(v, lazyRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -313,8 +328,12 @@ func NewValuesGeneratorFunc(values []string, templateFunctions template.FuncMap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTemplateFunc(value string, templateFunctions template.FuncMap) (func(data any) (string, error), bool) {
|
func createTemplateFunc(value string, lazyRoot func() *template.Template) (func(data any) (string, error), bool) {
|
||||||
tmpl, err := template.New("").Funcs(templateFunctions).Parse(value)
|
if !strings.Contains(value, "{{") {
|
||||||
|
return func(_ any) (string, error) { return value, nil }, false
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := lazyRoot().New("").Parse(value)
|
||||||
if err == nil && hasTemplateActions(tmpl) {
|
if err == nil && hasTemplateActions(tmpl) {
|
||||||
var err error
|
var err error
|
||||||
return func(data any) (string, error) {
|
return func(data any) (string, error) {
|
||||||
@@ -340,7 +359,7 @@ type keyValueItem interface {
|
|||||||
func buildKeyValueGenerators[T keyValueItem](
|
func buildKeyValueGenerators[T keyValueItem](
|
||||||
localRand *rand.Rand,
|
localRand *rand.Rand,
|
||||||
items []T,
|
items []T,
|
||||||
templateFunctions template.FuncMap,
|
lazyRoot func() *template.Template,
|
||||||
) ([]keyValueGenerator, bool) {
|
) ([]keyValueGenerator, bool) {
|
||||||
isDynamic := false
|
isDynamic := false
|
||||||
generators := make([]keyValueGenerator, len(items))
|
generators := make([]keyValueGenerator, len(items))
|
||||||
@@ -350,7 +369,7 @@ func buildKeyValueGenerators[T keyValueItem](
|
|||||||
keyValue := types.KeyValue[string, []string](item)
|
keyValue := types.KeyValue[string, []string](item)
|
||||||
|
|
||||||
// Generate key function
|
// Generate key function
|
||||||
keyFunc, keyIsDynamic := createTemplateFunc(keyValue.Key, templateFunctions)
|
keyFunc, keyIsDynamic := createTemplateFunc(keyValue.Key, lazyRoot)
|
||||||
if keyIsDynamic {
|
if keyIsDynamic {
|
||||||
isDynamic = true
|
isDynamic = true
|
||||||
}
|
}
|
||||||
@@ -358,7 +377,7 @@ func buildKeyValueGenerators[T keyValueItem](
|
|||||||
// Generate value functions
|
// Generate value functions
|
||||||
valueFuncs := make([]func(data any) (string, error), len(keyValue.Value))
|
valueFuncs := make([]func(data any) (string, error), len(keyValue.Value))
|
||||||
for j, v := range keyValue.Value {
|
for j, v := range keyValue.Value {
|
||||||
valueFunc, valueIsDynamic := createTemplateFunc(v, templateFunctions)
|
valueFunc, valueIsDynamic := createTemplateFunc(v, lazyRoot)
|
||||||
if valueIsDynamic {
|
if valueIsDynamic {
|
||||||
isDynamic = true
|
isDynamic = true
|
||||||
}
|
}
|
||||||
@@ -381,7 +400,7 @@ func buildKeyValueGenerators[T keyValueItem](
|
|||||||
func buildStringSliceGenerator(
|
func buildStringSliceGenerator(
|
||||||
localRand *rand.Rand,
|
localRand *rand.Rand,
|
||||||
values []string,
|
values []string,
|
||||||
templateFunctions template.FuncMap,
|
lazyRoot func() *template.Template,
|
||||||
) (func() func(data any) (string, error), bool) {
|
) (func() func(data any) (string, error), bool) {
|
||||||
// Return a function that returns an empty string generator if values is empty
|
// Return a function that returns an empty string generator if values is empty
|
||||||
if len(values) == 0 {
|
if len(values) == 0 {
|
||||||
@@ -393,7 +412,7 @@ func buildStringSliceGenerator(
|
|||||||
valueFuncs := make([]func(data any) (string, error), len(values))
|
valueFuncs := make([]func(data any) (string, error), len(values))
|
||||||
|
|
||||||
for i, value := range values {
|
for i, value := range values {
|
||||||
valueFunc, valueIsDynamic := createTemplateFunc(value, templateFunctions)
|
valueFunc, valueIsDynamic := createTemplateFunc(value, lazyRoot)
|
||||||
if valueIsDynamic {
|
if valueIsDynamic {
|
||||||
isDynamic = true
|
isDynamic = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -484,13 +484,11 @@ func newHostClients(
|
|||||||
proxiesRaw[i] = url.URL(proxy)
|
proxiesRaw[i] = url.URL(proxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
maxConns := max(fasthttp.DefaultMaxConnsPerHost, workers)
|
|
||||||
maxConns = ((maxConns * 50 / 100) + maxConns)
|
|
||||||
return NewHostClients(
|
return NewHostClients(
|
||||||
ctx,
|
ctx,
|
||||||
timeout,
|
timeout,
|
||||||
proxiesRaw,
|
proxiesRaw,
|
||||||
maxConns,
|
workers,
|
||||||
requestURL,
|
requestURL,
|
||||||
skipCertVerify,
|
skipCertVerify,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user