Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
To: Serge Petrenko <sergepetrenko@tarantool.org>, korablev@tarantool.org
Cc: tarantool-patches@dev.tarantool.org
Subject: Re: [Tarantool-patches] [PATCH 1/2] box: speed up tuple_field_map_create
Date: Tue, 1 Dec 2020 23:04:09 +0100	[thread overview]
Message-ID: <76a500bf-baa4-fc72-825d-ce324a190abf@tarantool.org> (raw)
In-Reply-To: <301e2d4d-3534-d03e-4dec-84c72d4c351d@tarantool.org>

Thanks for the investigation!

>> Then we probably also could gain some perf by splitting these functions
>> into 2 versions with validate true and validate false. Because we always
>> know it at compile time. Would be cool to use templates for this, but not
>> sure if we can simply change tuple.c to tuple.cc only for that.
> 
> 
> You mean like that?
> 
> tuple_field_map_create(...) {
> 
> tuple_field_map_create_impl(..., true, ...);
> 
> }
> 
> tuple_field_map_create_unchecked(...) {
> 
> tuple_field_mp_create_impl(..., false, ...);
> 
> }
> 
> I tried this approach, it didn't give anything. tuple_field_map_create time 2.15 s.

No, I mean create 2 versions of tuple_field_map_create. It leads
to some code duplication, and we probably don't want to do that
this way. But if it will give notable perf increase, we may decide
to consider templates.

> Is this possible that compiler already evaluates `validate`?

I guess it can, but we can not be sure it will always do so.

Consider this diff. Super ugly, but should reveal if validate
matters. After all, we have at least 4 validate checks here. The
diff replaces it with 1.

====================
diff --git a/src/box/tuple_format.c b/src/box/tuple_format.c
index 6c9b2a255..5ee0c4484 100644
--- a/src/box/tuple_format.c
+++ b/src/box/tuple_format.c
@@ -859,12 +859,38 @@ tuple_format_required_fields_validate(struct tuple_format *format,
 
 static int
 tuple_field_map_create_plain(struct tuple_format *format, const char *tuple,
-			     bool validate, struct field_map_builder *builder)
+			     struct field_map_builder *builder)
+{
+	const char *pos = tuple;
+	uint32_t defined_field_count = mp_decode_array(&pos);
+	defined_field_count = MIN(defined_field_count,
+				  tuple_format_field_count(format));
+	if (unlikely(defined_field_count == 0))
+		return 0;
+
+	struct tuple_field *field;
+	struct json_token **token = format->fields.root.children;
+	for (uint32_t i = 0; i < defined_field_count; i++, token++, mp_next(&pos)) {
+		field = json_tree_entry(*token, struct tuple_field, token);
+		if (field->offset_slot != TUPLE_OFFSET_SLOT_NIL &&
+		    field_map_builder_set_slot(builder, field->offset_slot,
+					       pos - tuple, MULTIKEY_NONE,
+					       0, NULL) != 0) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int
+tuple_field_map_create_and_validate_plain(struct tuple_format *format,
+					  const char *tuple,
+					  struct field_map_builder *builder)
 {
 	struct region *region = &fiber()->gc;
 	const char *pos = tuple;
 	uint32_t defined_field_count = mp_decode_array(&pos);
-	if (validate && format->exact_field_count > 0 &&
+	if (format->exact_field_count > 0 &&
 	    format->exact_field_count != defined_field_count) {
 		diag_set(ClientError, ER_EXACT_FIELD_COUNT,
 			 (unsigned) defined_field_count,
@@ -881,28 +907,22 @@ tuple_field_map_create_plain(struct tuple_format *format, const char *tuple,
 		required_fields = format->required_fields;
 		goto end;
 	}
-
-	if (validate) {
-		required_fields = region_alloc(region, required_fields_sz);
-		memcpy(required_fields, format->required_fields,
-		       required_fields_sz);
-	}
+	required_fields = region_alloc(region, required_fields_sz);
+	memcpy(required_fields, format->required_fields,
+	       required_fields_sz);
 
 	struct tuple_field *field;
 	struct json_token **token = format->fields.root.children;
 	for (uint32_t i = 0; i < defined_field_count; i++, token++, mp_next(&pos)) {
 		field = json_tree_entry(*token, struct tuple_field, token);
-		if (validate) {
-			bool nullable = tuple_field_is_nullable(field);
-			if(!field_mp_type_is_compatible(field->type, pos,
-							nullable)) {
-				diag_set(ClientError, ER_FIELD_TYPE,
-					 tuple_field_path(field),
-					 field_type_strs[field->type]);
-				return -1;
-			}
-			bit_clear(required_fields, field->id);
+		bool nullable = tuple_field_is_nullable(field);
+		if(!field_mp_type_is_compatible(field->type, pos, nullable)) {
+			diag_set(ClientError, ER_FIELD_TYPE,
+				 tuple_field_path(field),
+				 field_type_strs[field->type]);
+			return -1;
 		}
+		bit_clear(required_fields, field->id);
 		if (field->offset_slot != TUPLE_OFFSET_SLOT_NIL &&
 		    field_map_builder_set_slot(builder, field->offset_slot,
 					       pos - tuple, MULTIKEY_NONE,
@@ -910,12 +930,9 @@ tuple_field_map_create_plain(struct tuple_format *format, const char *tuple,
 			return -1;
 		}
 	}
-
 end:
-	return validate ?
-	       tuple_format_required_fields_validate(format, required_fields,
-						     required_fields_sz) :
-	       0;
+	return tuple_format_required_fields_validate(format, required_fields,
+						     required_fields_sz);
 }
 
 /** @sa declaration for details. */
@@ -935,8 +952,11 @@ tuple_field_map_create(struct tuple_format *format, const char *tuple,
 	 * tuple field traversal may be simplified.
 	 */
 	if (format->fields_depth == 1) {
-		return tuple_field_map_create_plain(format, tuple, validate,
-						    builder);
+		if (validate) {
+			return tuple_field_map_create_and_validate_plain(
+				format, tuple, builder);
+		}
+		return tuple_field_map_create_plain(format, tuple, builder);
 	}
 
 	uint32_t field_count;

  reply	other threads:[~2020-12-01 22:04 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-14 17:28 [Tarantool-patches] [PATCH 0/2] reduce performance degradation introduced by JSON path indices Serge Petrenko
2020-11-14 17:28 ` [Tarantool-patches] [PATCH 1/2] box: speed up tuple_field_map_create Serge Petrenko
2020-11-14 18:00   ` Cyrill Gorcunov
2020-11-16  7:34     ` Serge Petrenko
2020-11-20 23:26   ` Vladislav Shpilevoy
2020-11-23 13:50     ` Serge Petrenko
2020-11-24 22:33       ` Vladislav Shpilevoy
2020-12-01  8:48         ` Serge Petrenko
2020-12-01 22:04           ` Vladislav Shpilevoy [this message]
2020-12-02  9:53             ` Serge Petrenko
2020-11-14 17:28 ` [Tarantool-patches] [PATCH 2/2] box: use tuple_field_raw_by_part where possible Serge Petrenko
2020-11-20 23:26   ` Vladislav Shpilevoy
2020-11-23 13:51     ` Serge Petrenko
2020-11-24 22:33       ` Vladislav Shpilevoy
2020-12-01  8:48         ` Serge Petrenko
2020-12-01 22:04           ` Vladislav Shpilevoy
2020-11-16  7:50 ` [Tarantool-patches] [PATCH 0/2] reduce performance degradation introduced by JSON path indices Serge Petrenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=76a500bf-baa4-fc72-825d-ce324a190abf@tarantool.org \
    --to=v.shpilevoy@tarantool.org \
    --cc=korablev@tarantool.org \
    --cc=sergepetrenko@tarantool.org \
    --cc=tarantool-patches@dev.tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH 1/2] box: speed up tuple_field_map_create' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox