According to profiling data, converting UUIDs to strings is a frequent
operation in some workloads. This typically results in a call to
xasprintf(), which internally calls vsnprintf() twice, first to
calculate the required buffer size, and then to format the string.
This patch introduces specialized functions for printing UUIDs, which
both reduces code duplication and improves performance.
For example, on my laptop, 10,000,000 calls to the new uuid_to_string()
function takes 1296 ms, while the same number of xasprintf() calls using
UUID_FMT take 2498 ms.
Signed-off-by: Dmitry Porokh <dporokh@nvidia.com>
Signed-off-by: Eelco Chaudron <echaudro@redhat.com>
Creating and destroying JSON objects may be time consuming.
Add json_serialized_object_create_with_yield() and
json_destroy_with_yield() functions that make use of the
cooperative multitasking module to yield during processing,
allowing time sensitive tasks in other parts of the program
to be completed during processing.
We keep these new functions private to OVS by adding a new
lib/json.h header file.
The include guard in the public include/openvswitch/json.h is
updated to contain the OPENVSWITCH prefix to be in line with the
other public header files, allowing us to use the non-prefixed
version in our private lib/json.h.
Signed-off-by: Frode Nordahl <frode.nordahl@canonical.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Refactoring of the replication code, so each database is handled
separately from each other. Supposed to work the same way as before
with the only difference that each backup database will have its own
connection to the source and will have its own state machine.
From the user's perspective, the only visible difference is that
ovsdb-server/sync-status appctl now shows the status of each
database separately.
If one of the connections is permanently broken, all the databases
will be switched to active. This is done in order to preserve the
old behavior where we had only one connection.
Acked-by: Dumitru Ceara <dceara@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
When reference counting for json objects was introduced the
old json_clone() function became json_deep_clone(), but it
still calls shallow json_clone() while cloning objects and
arrays not really producing a deep copy.
Fixing that by making other functions to perform a deep copy
as well. There are no users for this functionality inside
OVS right now, but OVS exports this functionality externally.
'ovstest test-json' extended to test both versions of a clone
on provided inputs.
Fixes: 9854d473adea ("json: Use reference counting in JSON objects")
Acked-by: Dumitru Ceara <dceara@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
To parse a json string prior to this change, json_lex_input is called
with each character of the string. If the character needs to be copied
to the buffer, it is copied individually. This is an expensive
operation, as often there are multiple characters in a row
that need to be copied, and copying memory in blocks is more efficient
than byte by byte. To improve this, the string is now copied
in blocks with an offset counter. A copy is performed when the parser
state equals done.
Functions that are called for each character use a lot of CPU cycles.
Making these functions inline greatly reduces the cycles used and
improves overall performance. Since json_lex_input was only needed in
one place, it doesn't have to be its own function.
There is also a conditional that checks if the current character is a
new line, which is quite unlikely. When this was examined with perf, the
comparison had a very high CPU cycle usage. To improve this, the
OVS_UNLIKELY macro was used, which forces the compiler to switch the
order of the instructions.
Here is the improvement seen in the json-string-benchmark test:
SIZE Q S BEFORE AFTER CHANGE
--------------------------------------------------------
100000 0 0 : 0.842 ms 0.489 ms -41.9 %
100000 2 1 : 0.917 ms 0.535 ms -41.7 %
100000 10 1 : 1.063 ms 0.656 ms -38.3 %
10000000 0 0 : 85.328 ms 49.878 ms -41.5 %
10000000 2 1 : 92.555 ms 54.778 ms -40.8 %
10000000 10 1 : 106.728 ms 66.735 ms -37.5 %
100000000 0 0 : 955.375 ms 621.950 ms -34.9 %
100000000 2 1 : 1031.700 ms 665.200 ms -35.5 %
100000000 10 1 : 1189.300 ms 796.050 ms -33.0 %
Here Q is probability (%) for a character to be a '\"' and
S is probability (%) to be a special character ( < 32).
Signed-off-by: Rosemarie O'Riorden <roriorden@redhat.com>
Acked-by: Dumitru Ceara <dceara@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Using SHORT version of the *_SAFE loops makes the code cleaner and less
error prone. So, use the SHORT version and remove the extra variable
when possible for hmap and all its derived types.
In order to be able to use both long and short versions without changing
the name of the macro for all the clients, overload the existing name
and select the appropriate version depending on the number of arguments.
Acked-by: Dumitru Ceara <dceara@redhat.com>
Acked-by: Eelco Chaudron <echaudro@redhat.com>
Signed-off-by: Adrian Moreno <amorenoz@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
With the next commit reference counting of json objects will take
significant part of the CPU time for ovsdb-server. Inlining them
to reduce the cost of a function call.
Acked-by: Mike Pattrick <mkp@redhat.com>
Acked-by: Dumitru Ceara <dceara@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Introducing a new json type JSON_SERIALIZED_OBJECT. It's not an
actual type that can be seen in a json message on a wire, but
internal type that is intended to hold a serialized version of
some other json object. For this reason it's defined after the
JSON_N_TYPES to not confuse parsers and other parts of the code
that relies on compliance with RFC 4627.
With this JSON type internal users may construct large JSON objects,
parts of which are already serialized. This way, while serializing
the larger object, data from JSON_SERIALIZED_OBJECT can be added
directly to the result, without additional processing.
This will be used by next commits to add pre-serialized JSON data
to the raft_header structure, that can be converted to a JSON
before writing the file transaction on disk or sending to other
servers. Same technique can also be used to pre-serialize json_cache
for ovsdb monitors, this should allow to not perform serialization
for every client and will save some more memory.
Since serialized JSON is just a string, reusing the 'json->string'
pointer for it.
Acked-by: Dumitru Ceara <dceara@redhat.com>
Acked-by: Han Zhou <hzhou@ovn.org>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Current string serialization code puts all characters one by one.
This is slow because dynamic string needs to perform length checks
on every ds_put_char() and it's also doesn't allow compiler to use
better memory copy operations, i.e. doesn't allow copying few bytes
at once.
Special symbols are rare in a typical database. Quotes are frequent,
but not too frequent. In databases created by ovn-kubernetes, for
example, usually there are at least 10 to 50 chars between quotes.
So, it's better to count characters that doesn't require escaping
and use fast data copy for the whole sequential block.
Testing with a synthetic benchmark (included) on my laptop shows
following performance improvement:
Size Q S Before After Diff
-----------------------------------------------------
100000 0 0 : 0.227 ms 0.142 ms -37.4 %
100000 2 1 : 0.277 ms 0.186 ms -32.8 %
100000 10 1 : 0.361 ms 0.309 ms -14.4 %
10000000 0 0 : 22.720 ms 12.160 ms -46.4 %
10000000 2 1 : 27.470 ms 19.300 ms -29.7 %
10000000 10 1 : 37.950 ms 31.250 ms -17.6 %
100000000 0 0 : 239.600 ms 126.700 ms -47.1 %
100000000 2 1 : 292.400 ms 188.600 ms -35.4 %
100000000 10 1 : 387.700 ms 321.200 ms -17.1 %
Here Q - probability (%) for a character to be a '\"' and
S - probability (%) to be a special character ( < 32).
Testing with a closer to real world scenario shows overall decrease
of the time needed for database compaction by ~5-10 %. And this
change also decreases CPU consumption in general, because string
serialization is used in many different places including ovsdb
monitors and raft.
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Acked-by: Numan Siddique <numans@ovn.org>
Acked-by: Dumitru Ceara <dceara@redhat.com>
Several OVS structs contain embedded named unions, like this:
struct {
...
union {
...
} u;
};
C11 standardized a feature that many compilers already implemented
anyway, where an embedded union may be unnamed, like this:
struct {
...
union {
...
};
};
This is more convenient because it allows the programmer to omit "u."
in many places. OVS already used this feature in several places. This
commit embraces it in several others.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Justin Pettit <jpettit@ovn.org>
Tested-by: Alin Gabriel Serdean <aserdean@ovn.org>
Acked-by: Alin Gabriel Serdean <aserdean@ovn.org>
Until now, every time the JSON parser added an object member, it made an
extra copy of the member name and then freed the original copy. This is
wasteful, so this commit eliminates the extra copy.
Signed-off-by: Ben Pfaff <blp@ovn.org>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
This warning breaks the build on travis:
lib/json.c:1627:12: error: symbol 'chars_escaping' was not declared.
Should it be static?
CC: Esteban Rodriguez Betancourt <estebarb@hpe.com>
Reported-At: https://travis-ci.org/openvswitch/ovs/jobs/165300417
Fixes: 644ecb10a661 ("json: Serialize strings using a lookup table")
Signed-off-by: Joe Stringer <joe@ovn.org>
Acked-by: Ben Pfaff <blp@ovn.org>
The existing implementation uses a switch with
many conditions, that when compiled is translated
to a not optimal series of conditional jumps.
With a lookup table the generated code has less conditional jumps,
that should translate in improving the CPU ability to predict the
jumps.
Performance Comparison:
All the timings are in nanoseconds, "OVS Master" corresponds to 13a1d36.
N is the number of repetitions
Serialize vswitch.ovsschema
N OVS Master Lookup Table Difference Diff per op
1 233182 200369 32813 32813
10 2724931 1919168 805763 80576.3
100 22802794 24406648 -1603854 -16038.54
1000 253645888 206259760 47386128 47386.128
10000 2352245703 1906839780 445405923 44540.5923
100000 23967770920 19012178655 4955592265 49555.92265
Serialize echo example
N OVS Master Lookup Table Difference Diff per op
1 3857 12565 -8708 -8708
10 17403 7312 10091 1009.1
100 57859 56613 1246 12.46
1000 592310 528110 64200 64.2
10000 6096334 5576109 520225 52.0225
100000 60970439 58477626 2492813 24.92813
Serialize mutate example
N OVS Master Lookup Table Difference Diff per op
1 7115 19051 -11936 -11936
10 34110 39561 -5451 -545.1
100 296613 298645 -2032 -20.32
1000 3510499 2930588 579911 579.911
10000 33898710 30278631 3620079 362.0079
100000 305069356 280622992 24446364 244.46364
Signed-off-by: Esteban Rodriguez Betancourt <estebarb@hpe.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
After profiling OVSDB insert performance it was found
that some significant portion of its time OVSDB is
calling the function json_clone.
Also, the current usages of json_clone never modify the json,
just keeps it to prevent it to be freed.
With that in mind the struct json, json_create, json_clone
and json_destroy were modified to keep a count of how many
references of the json struct are left. Only when that count
reaches zero the json struct is freed.
The old "json_clone" function was renamed as "json_deep_clone".
Some examples of the performance difference:
In these tests a test table with 4 columns (string, string,
bool, integer) was used. All the tests used "commit block".
*** 50 process each inserting 1000 rows ***
Master OVS
Test Duration 131 seconds
Average Inserts Per second 746.2687 inserts/s
Average Insert Duration 134.1382 ms
Minimal Insert Duration 0.166202 ms
Maximum Insert Duration 489.8593 ms
JSON GC Patch
Test Duration 86 seconds
Average Inserts Per second 1176 inserts/s
Average Insert Duration 82.26761 ms
Minimal Insert Duration 0.165448 ms
Maximum Insert Duration 751.2111 ms
*** 5 process each inserting 10000 rows ***
Master OVS
Test Duration 8 seconds
Average Inserts Per second 7142.857 inserts/s
Average Insert Duration 0.656431 ms
Minimal Insert Duration 0.125197 ms
Maximum Insert Duration 11.93203 ms
JSON GC Patch
Test Duration 7 seconds
Average Inserts Per second 8333.333 inserts/s
Average Insert Duration 0.55688 ms
Minimal Insert Duration 0.143233 ms
Maximum Insert Duration 26.26319 ms
Signed-off-by: Esteban Rodriguez Betancourt <estebarb@hpe.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
To easily allow both in- and out-of-tree building of the Python
wrapper for the OVS JSON parser (e.g. w/ pip), move json.h to
include/openvswitch. This also requires moving lib/{hmap,shash}.h.
Both hmap.h and shash.h were #include-ing "util.h" even though the
headers themselves did not use anything from there, but rather from
include/openvswitch/util.h. Fixing that required including util.h
in several C files mostly due to OVS_NOT_REACHED and things like
xmalloc.
Signed-off-by: Terry Wilson <twilson@redhat.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
This allows OVN to take advantage of the client scalability changes
that have been committed to ovsdb-server on master recently.
Conflicts:
Makefile.am
lib/learn.c
The error message should not include bytes already copied from the input
string.
Found by inspection.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Alex Wang <alexw@nicira.com>
This saves some cut-and-paste duplicated code elsewhere and will have
additional users in upcoming commits.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Russell Bryant <rbryant@redhat.com>
The following macros are renamed to avoid conflicts with other headers:
* WARN_UNUSED_RESULT to OVS_WARN_UNUSED_RESULT
* PRINTF_FORMAT to OVS_PRINTF_FORMAT
* NO_RETURN to OVS_NO_RETURN
Signed-off-by: Thomas Graf <tgraf@noironetworks.com>
Acked-by: Ben Pfaff <blp@nicira.com>
nodes is allocated through shash_sort() but never freed.
Signed-off-by: Thomas Graf <tgraf@noironetworks.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
json_string_unescape() flagged a backslash at the end of a string as an
error, but of course "\\" is a valid string. This fixes the problem.
VMware-BZ: #1275208
Reported-by: Michael Hu <mhu@nicira.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Alex Wang <alexw@nicira.com>
This reverts commit 1600fa6853872e16130366351a2c14f6fa8b547c.
Connections that queue up too much data, because they are monitoring a
table that is changing quickly and failing to keep up with the updates,
cause problems with buffer management. Since commit 60533a405b2e
(jsonrpc-server: Disconnect connections that queue too much data.),
ovsdb-server has dealt with them by disconnecting the connection and
letting them start up again with a fresh copy of the database. However,
this is not ideal because of situations where disconnection happens
repeatedly. For example:
- A manager toggles a column back and forth between two or more values
quickly (in which case the data transmitted over the monitoring
connections always increases quickly, without bound).
- A manager repeatedly extends the contents of some column in some row
(in which case the data transmitted over the monitoring connection
grows with O(n**2) in the length of the string).
A better way to deal with this problem is to combine updates when they are
sent to the monitoring connection, if that connection is not keeping up.
In both the above cases, this reduces the data that must be sent to a
manageable amount. An upcoming patch implements this new way. This commit
reverts part of the previous solution that disconnects backlogged
connections, since it is no longer useful.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Andy Zhou <azhou@nicira.com>
This allows other libraries to use util.h that has already
defined NOT_REACHED.
Signed-off-by: Harold Lim <haroldl@vmware.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
where it can't be EOF, cast a value to unsigned char before passing it
to ctype functions to avoid unintended sign extension.
Signed-off-by: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
Signed-off-by: Ben Pfaff <blp@nicira.com>
This is a straight search-and-replace, except that I also removed #include
<assert.h> from each file where there were no assert calls left.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Ethan Jackson <ethan@nicira.com>
Casts are sometimes necessary. One common reason that they are necessary
is for discarding a "const" qualifier. However, this can impede
maintenance: if the type of the expression being cast changes, then the
presence of the cast can hide a necessary change in the code that does the
cast. Using CONST_CAST, instead of a bare cast, makes these changes
visible.
Inspired by my own work elsewhere:
http://git.savannah.gnu.org/cgit/pspp.git/tree/src/libpspp/cast.h#n80
Signed-off-by: Ben Pfaff <blp@nicira.com>
Replaced all instances of Nicira Networks(, Inc) to Nicira, Inc.
Feature #10593
Signed-off-by: Raju Subramanian <rsubramanian@nicira.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
When json_lex_input() returns false, the parser does not consume the byte
passed in. That byte will get processed again in the next iteration of
the json_parser_feed() loop. Therefore, until now, this code has
double-counted bytes that cause a false return from json_lex_input().
This fixes the problem. Every input byte is now counted only once.
Signed-off-by: Ben Pfaff <blp@nicira.com>
All of these changes avoid using the same name for two local variables
within a same function. None of them are actual bugs as far as I can tell,
but any of them could be confusing to the casual reader.
The one in lib/ovsdb-idl.c is particularly brilliant: inner and outer
loops both using (different) variables named 'i'.
Found with GCC -Wshadow.
RFC 4627 (which defines JSON) says:
The names within an object SHOULD be unique.
In my view, this means that the treatment of duplicate names within a
JSON object is more or less up to the implementation. Until now, the OVS
JSON parser has dealt with duplicates fairly badly: they all get shoved
into the hash table and you get one or the other value semi-randomly
(typically the one added later). This commit makes the behavior
predictable: old values are deleted and replaced by newer values.
Some upcoming code wants to serialize JSON into a "struct ds" dynamic
string buffer, so expose an interface to do this.
This commit doesn't change much, but it renames some functions internal
to json.c to make the naming more consistent.
Also, make jsonrpc_log_msg() use this new function, since it is a more
straightforward way to do what it wants.
The JSON syntax for strings is very reasonable. An upcoming commit will
have a need for a string parser, so make the JSON string parser available
for that.
Also, this change improves the error message for strings that end in the
middle of a \u sequence, so update the tests to match.
The chroots in which we often build Open vSwitch don't have /proc and
thus cannot support /dev/stdin, because on Linux that is a symlink to
/proc/self/fd/0. So avoid using /dev/stdin in the testsuite.
The test for whether a real number was outside the valid range was
imprecise and failed at the edge of the real range. This commit changes
the code to use the C library's strtod(), which presumably does better.