[libvirt] [PATCH 6/7] Switch to filtering based on log source name instead of filename
Daniel P. Berrange
berrange at redhat.com
Mon Mar 10 10:18:58 UTC 2014
On Fri, Mar 07, 2014 at 11:05:28AM -0700, Eric Blake wrote:
> On 03/03/2014 12:18 PM, Daniel P. Berrange wrote:
> > Both
> > of these options have a notable performance impact, however, and
> > it is believed that worst case behaviour where the fields are
> > read concurrently with being written would merely result in an
> > mistaken emissions or dropping of the log message in question.
> > This is an acceptable tradeoff for the performance benefit of
> > avoiding locking.
> >
>
> Almost. As long as writes are safe, the worst that can happen is we
> fail to emit a message that just got enabled, or we emit a message that
> just got disabled. But had we used locks to avoid this race, and the
> locks get obtained in reverse order, we would see the same behavior. So
> the locks add no protection, and eliding them in favor of simpler
> non-atomic integer ops is a safe action.
>
> If there were only a single writer, then writes would be automatically
> safe. However, you have multiple writers. Thus, you have the situation
> that if two writers both try to increment the global serial with no
> locks or atomic increments, you could end up with the classic symptoms
> of over- or under-incrementing the global serial. If three threads compete:
>
> start: global is 1
> thread one: read global to compute its increment
> thread two: read global to compute its increment
> thread two: write the increment, global is now 2
> thread three: compare local 0 against global 2, recompute priority
> thread one: write the increment, global is now 2
> thread three: compare local 2 against global 2, no priority recompute
>
> Oops - if thread one changed priority so that thread three should no
> longer log, we've messed up, and may have LOTS of messages logged that
> should not have been, rather than just one or two at the race boundary
> case. So I think your _increments_ need to be atomic, to protect the
> writers, but those are not the hot path; while the READS of the global
> can remain unprotected, and those are the actual hot path you are
> optimizing in this patch.
The writes are already protected by a mutex so I don't think we need
to use atomic ops for increment either.
> > static virLogFilterPtr virLogFilters = NULL;
> > static int virLogNbFilters = 0;
> >
> > @@ -514,6 +515,7 @@ virLogResetFilters(void)
> > VIR_FREE(virLogFilters[i].match);
> > VIR_FREE(virLogFilters);
> > virLogNbFilters = 0;
> > + virLogFiltersSerial++;
> > return i;
> > }
> >
> > @@ -569,6 +571,7 @@ virLogDefineFilter(const char *match,
> > virLogFilters[i].priority = priority;
> > virLogFilters[i].flags = flags;
> > virLogNbFilters++;
> > + virLogFiltersSerial++;
>
> These are the increments that I think are not hotpath, and need to be
> serialized with an atomic increment.
These two functions run with the global log mutex held, so there can
only be one writer at a time.
>
> >
> > +static void
> > +virLogSourceUpdate(virLogSourcePtr source)
> > +{
> > + virLogLock();
>
> The common case is that the per-log serial will match the global serial;
> while holding the lock on the boundary case of an updated global serial
> is not going to affect hot case.
>
> > /*
> > - * check against list of specific logging patterns
> > + * 3 intentionally non-thread safe variable reads.
> > + * Worst case result is a log message is accidentally
> > + * dropped or emitted, if another thread is updating
> > + * log filter list concurrently with a log message
>
> and again, if we WERE thread-safe, the race could have always been won
> the other way in obtaining the lock, for the same end result, so our
> lack of thread-safety isn't critical.
>
> > */
> > - fprio = virLogFiltersCheck(filename, &filterflags);
> > - if (fprio == 0) {
> > - if (priority < virLogDefaultPriority)
> > - emit = false;
> > - } else if (priority < fprio) {
> > - emit = false;
> > - }
> > -
> > - if (!emit)
> > + if (source->serial < virLogFiltersSerial)
> > + virLogSourceUpdate(source);
> > + if (priority < source->priority)
> > goto cleanup;
> > + filterflags = source->flags;
>
> Makes sense.
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the libvir-list
mailing list