Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 23 Oct 2001 14:03:19 -0700
From:      Luigi Rizzo <rizzo@aciri.org>
To:        Garrett Wollman <wollman@khavrinen.lcs.mit.edu>
Cc:        net@FreeBSD.ORG
Subject:   Re: performance issues with M_PREPEND on clusters
Message-ID:  <20011023140318.A35869@iguana.aciri.org>
In-Reply-To: <200110231917.f9NJH4T32996@khavrinen.lcs.mit.edu>
References:  <20011023110307.A34494@iguana.aciri.org> <200110231917.f9NJH4T32996@khavrinen.lcs.mit.edu>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, Oct 23, 2001 at 03:17:04PM -0400, Garrett Wollman wrote:
> <<On Tue, 23 Oct 2001 11:03:07 -0700, Luigi Rizzo <rizzo@aciri.org> said:
> 
> > Similar things could be done in m_pullup() to avoid the
> > extra allocation.
> 
> Can't be done in m_pullup: the whole purpose of m_pullup is to
> *guarantee* that the data in question will never be shared.  It might
> be worth having a new interface which doesn't provide such a
> guarantee.

You are right, we cannot change the semantics of m_pullup() without
carefully analysing how it is used, and this definitely calls for
one or two new interfaces (m_pullup_readonly(), m_pullup_writable()).

Technically, it is correct that m_pullup guarantees that the data
in question will never be shared, but it seems to me more an artifact
of its implementation than a real goal.

From what i see, m_pullup() is mostly used to make sure that a
block is contiguous, and in some other cases to have a writable
copy of the block. In both cases being able to write into the
cluster would save a bit of work.

Yes, there are situations (e.g. where you are replicating a packet
and changing some things in the header for each replica -- see
EXAMPLE 1) where the current semantics of m_pullup() _seems_ to
save something, but this comes at the price of an m_copy() so there
is really no saving compared to EXAMPLE 2.

By having the new m_pullup_XXX() calls, you could rewrite the same
code as in EXAMPLE 3, with the advantage that the first instance
could turn into a no-op, and you replicate only if really necessary.

	cheers
	luigi

-----------------------------------------------------------------

    EXAMPLE 1: /* some pieces of the kernel are like this */

	m = m_pullup(m, some_len);
	for (;;) {
	    <change something in the private part of m>
	    n = m_copy(m, 0, M_COPYALL);
	    <pass n around>
	    if (some_condition)
		break ;
	}
	m_free(m);

    EXAMPLE 2: /* they could be rewritten in this way */

	canfree = 1;
	for (;;) {
	    n = m_pullup(m, some_len);
	    if (n == m)
		canfree=0;
	    <change something in the private part of n>
	    <pass n around>
	    if (some_condition)
		break ;
	}
	if (canfree)
	    m_free(m);

    EXAMPLE 3: /* or in this way with a new m_pullupXXX() interface */
	    
	for (;;) {
	    n = m_pullup_writable(m, some_len);
	    if (n == m)
		canfree=0;
	    <change something in n>
	    <pass n around>
	    if (some_condition)
		break ;
	}
	if (canfree)
	    m_free(m);
	

----------------------------------+-----------------------------------------
 Luigi RIZZO, luigi@iet.unipi.it  . ACIRI/ICSI (on leave from Univ. di Pisa)
 http://www.iet.unipi.it/~luigi/  . 1947 Center St, Berkeley CA 94704
 Phone: (510) 666 2927
----------------------------------+-----------------------------------------

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20011023140318.A35869>