Fix: condition: buffer-usage: use double instead of fixed point
Issue observed
==============
When running the test_notification_ust_buffer_usage test on x86
(32 bit), the session daemon and test client both crash. The session
daemon dies while attempting to lock a NULL client list during the
execution of an enqueued action in the action executor.
See the following backtrace:
#0 0xf7c6c756 in __GI___pthread_mutex_lock (mutex=0x0) at ../nptl/pthread_mutex_lock.c:67
#1 0x565afe96 in notification_client_list_send_evaluation (client_list=0x0, trigger=0xf0f225e0, evaluation=0xf330c830, source_object_creds=0xf330e5cc, client_report=0x565cf81b <client_handle_transmission_status>, user_data=0xf330c320) at notification-thread-events.c:4372
#2 0x565cfb41 in action_executor_notify_handler (executor=0xf330c320, work_item=0xf330e5b0, item=0xf330c7b0) at action-executor.c:269
#3 0x565d1a58 in action_executor_generic_handler (executor=0xf330c320, work_item=0xf330e5b0, item=0xf330c7b0) at action-executor.c:696
#4 0x565d1b7f in action_work_item_execute (executor=0xf330c320, work_item=0xf330e5b0) at action-executor.c:715
#5 0x565d212f in action_executor_thread (_data=0xf330c320) at action-executor.c:797
#6 0x565b9d0e in launch_thread (data=0xf330c390) at thread.c:66
#7 0xf7c69fd2 in start_thread (arg=<optimized out>) at pthread_create.c:486
#8 0xf7b7f6d6 in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:108
This crash causes an assertion to fail in the test client; checking for
data pending was not expected to return a negative value. In this case,
the negative return value is justified as it is -LTTNG_ERR_NO_SESSIOND.
Cause
=====
Equipped with coffee, a debugger, and a healthy dose of print
statements, it appeared that the following was taking place:
- Register a trigger (T1): high buffer usage (0.99) -> notify (succeeds)
- Subscribe to high buffer usage (0.99) notifications (succeeds)
- Subscribe to high buffer usage (0.99) notifications
(fails duplicate, expected)
- Unregister trigger (fails unexpectedly)
- Notification client destroys its channel, causing the condition to be
unsubscribed-from
- Another test registers a trigger (T2): high buffer usage (0.90) ->
notify (succeeds)
- Session daemon evaluates a channel sample against T1's condition,
which evaluates to true and produces an "evaluation" to send to
clients
- The client list associated to T1's condition is not found (but this
isn't checked)
- An action executor work item is queued to run T1's actions (notify),
but without a client list, resulting in the crash when it is executed.
We could confirm that the client list associated to T1's condition was
created and never destroyed making the failure to find it rather
puzzling.
It turns out that the hash of T1's condition did not match the hash of
the client list's condition. This is unexpected as both conditions are
copies of one another.
It turns out that, on x86, the scheme being used to transmit the
condition's buffer usage threshold floating point value is not compiled
to numerically stable code. Serializing such a buffer condition and
creating it from the resulting payload in a loop showed that the
threshold value gradually drifted. This isn't the case on the other
architectures we support.
On x86-64, gcc makes use of SSE instructions to perform the conversion
to an integral value (with double precision). However, on x86, it makes
use of the x87 fpu stack instructions which carry 80-bit of precision
internally, resulting in a loss of precision as the value is
transformed, back and forth, between 80-bit to double precision
representations.
Solution
========
Since conditions are not carried between hosts (only between clients
and the session daemon), a fixed-point conversion scheme is unnecessary.
The 'double' value provided by the client is carried directly which
bypasses the problem completely.
Drawbacks
=========
None.
Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: Ie524e7362626406327f4f56e1dba5c8cf469df31
This page took 0.027992 seconds and 4 git commands to generate.