[comp.arch] Do every object based systems suffer from poor performance ?

kong@CS.UCLA.EDU (05/15/87)

[I posted this article to comp.sys.intel, and I guess many of you might be
interested in this issue also.]

Here is an interesting issue,
What are the pros and cons of object based (or capability based) systems, say
iAPX 432, in terms of protection mechanisms compared to the conventional
systems, say 80286, from the architecture's point of view ?

Here are some comparisons between them,
1. protection granularity
	80286 uses segments as the basic protection unit.
	432 uses objects.

2. protection implementation
	80286 uses global and local descriptor tables(GDT and LDT) to define
	the rights to access the segments. Each memory reference has to check
	those access rights.
	432 uses Access Descriptors (actually, capabilities) to define the
	access right the user's process has.

3. protection hierarchy
	80286 uses ring structured protection hierarchy. The inner most ring is
	the most trusted OS kernel, the outer ring is the user's process. Each
	ring has a privilege level which defines the current process privilege,
	the privilege level will change as the process call a function which 
	resides at the inner ring.
	432 uses plain object spaces. There is no hierarchical structure. User
	can access every objects as long as he has the right capability.

4. instruction set
	80286 has certain privileged instructions which can only be executed
	in the kernel mode. This is the direct consequence of the ring structure	and use the segment as the basic protection unit.
	in 432, you can execute every instructions as long as you have the right	capability to access the instruction object.

5. sharing
	80286 uses some sharable LDT or aliases to share some data or 
        instructions between some processes. Or you can put them into GDT to be 
	shared by every processes in the system.
	432 sharing is achieved by passing capabilities to the sharable object.

***	It seems the conventional architecture such as 80286 has different
	approaches for different problems (i.e. privilege level, ring,...).
	Sometimes it seems that the conventional architecture can't guarantee
	a true protection. On the other hand, the architecture of 432 is very 
	uniform; it solves each problems by using the same approach (I.e. 
	the object model), but it has severe ovehead for object access. As we 
	know, the 432 suffers from the slow performance problems which is a 
	direct consequence of this "safest" object model. As a matter of fact, 
	every object based systems has this kind of problems. So, what should 
	be our choice ? a conventional architecture whose performance is
	acceptable but sometimes has protection problems, or a object based 
	system which has less protection problems but an (unacceptable ?) poor 
	performance ? (I know that at least the current object or capability
	based systems are very slow, hope we'll see some high performance
	object based systems.....)

'Kong
UUCP : ..!{sdcrdcf,ihnp4,cepu,trwspp,ucbvax}!ucla-cs!kong
ARPA : kong@cs.ucla.edu 

kempf@hplabsc.UUCP (Jim Kempf) (05/15/87)

In article <6055@shemp.UCLA.EDU>, kong@CS.UCLA.EDU writes:
> 
> 	direct consequence of this "safest" object model. As a matter of fact, 
> 	every object based systems has this kind of problems. So, what should 
> 	be our choice ? a conventional architecture whose performance is
> 	acceptable but sometimes has protection problems, or a object based 
> 	system which has less protection problems but an (unacceptable ?) poor 
> 	performance ? (I know that at least the current object or capability

The statement that "every object based system" has poor performance is
simply not true. Software object based systems on conventional hardware
can get performance which is very good. Objective-C(TM), for example,
has messaging speed of about 3X a function call (~30 microseconds
on a 16.5 MHx 68020), C++ can get full function call speed for nonvirtual
(noninherited) functions, or, for the cost of one level of indirection,
inherited functions can be used. The Common Lisp Object System (new
standard for Common Lisp o-o programming) can get about 4X a function call
for single argument (Smalltalk-like) dispatching, but for that, you
can also write methods which dispatch on integers, symbols, and other
built-in Common Lisp data types (which you can't do in Objective-C),
and have dynamic lookup of methods at run time (which you can't do in
C++).

		Jim Kempf	kempf@hplabs.hp.com

ark@alice.UUCP (05/16/87)

In article <1831@hplabsc.UUCP>, kempf@hplabsc.UUCP writes:
> C++ can get full function call speed for nonvirtual
> (noninherited) functions, or, for the cost of one level of indirection,
> inherited functions can be used.

and later writes:
> and have dynamic lookup of methods at run time (which you can't do in
> C++).

Two small corrections.

First, "virtual" != "inherited".  If, for example, I say:

	class Foo {
	public:
		f();
	};

	class Bar: public Foo {
	public:
		g();
	};

	Foo foo;
	Bar bar;

then calling foo.f(), bar.g(), and bar.f() all require the same amount
of overhead, which is equal to an ordinary C function call.

Second, C++ does have dynamic lookup of methods at run time -- that's
what "virtual" is for:

	class Foo {
	public:
		virtual void print();
	};

	class Bar: public Foo {
	public:
		void print();
	};

	Foo foo;
	Bar bar;
	Foo* fp1;
	Foo* fp2;

	fp1 = &foo;
	fp2 = &bar;

Now calling foo.print() and bar.print() still take the same overhead as
a C function call, because the compiler can determine the type of foo
and bar statically.  Calling fp1->print() and fp2->print() involve
dynamic lookup, because even though fp1 and fp2 are declared to be
Foo pointers, they can really point to a Foo or anything derived from
it. In this example, fp1->print() will call the Foo print function
and fp2->print() would call the Bar print function.

This dynamic lookup requires one extra memory reference per call.

benson@alcatraz.ksr.com (Benson Margulies) (05/17/87)

In article <1831@hplabsc.UUCP> kempf@hplabsc.UUCP (Jim Kempf) writes:
>> 	performance ? (I know that at least the current object or capability
>
>The statement that "every object based system" has poor performance is
>simply not true. Software object based systems on conventional hardware
>can get performance which is very good. 

I think that there has to be a distinction betwen object oriented
programming and capability architecture. A capability architecture is
a lot more than a hardware implementation of object orientated
programming. It is a particular approach to data security/integrity.
You can have a completely conventional programming environment on a
capability environment, where a capability is just a pointer to a
piece of data structure. YOu can do object oriented programming on
hardware that don't know anything from Security.

The Symbolics 36xx series has architectural support for flavors, but
not a hint of a capability.



Benson I. Margulies                         Kendall Square Research Corp.
harvard!ksr!benson			    All comments the responsibility
ksr!benson@harvard.harvard.edu		    of the author, if anyone.

kempf@hplabsc.UUCP (Jim Kempf) (05/17/87)

In article <6894@alice.UUCP>, ark@alice.UUCP writes:

> > C++ can get full function call speed for nonvirtual
> > (noninherited) functions, or, for the cost of one level of indirection,
> > inherited functions can be used.
> 
> and later writes:
> > and have dynamic lookup of methods at run time (which you can't do in
> > C++).
> 
> Two small corrections.
> 
> First, "virtual" != "inherited".  If, for example, I say:
> 
> 	class Foo {
> 	public:
> 		f();
> 	};
> 
> 	class Bar: public Foo {
> 	public:
> 		g();
> 	};
> 
> 	Foo foo;
> 	Bar bar;
> 
> then calling foo.f(), bar.g(), and bar.f() all require the same amount
> of overhead, which is equal to an ordinary C function call.
> 

I don't see how this invalidates my point. My understanding is that
g() is defined on the class Bar (and thus not inherited) and f()
is defined on the class Foo (and thus not inherited). Since foo is
of type Foo and bar is of type Bar, invoking foo.f() is invoking
a noninherited function and invoking bar.g() is invoking a noninherited
function. Since types are declared at compile time in C++, the
compiler presumably arranges for the proper function to get inserted.
From your example, neither g() nor f() are declared virtual.

> Second, C++ does have dynamic lookup of methods at run time -- that's
> what "virtual" is for:
> 
> 	class Foo {
> 	public:
> 		virtual void print();
> 	};
> 
> 	class Bar: public Foo {
> 	public:
> 		void print();
> 	};
> 
> 	Foo foo;
> 	Bar bar;
> 	Foo* fp1;
> 	Foo* fp2;
> 
> 	fp1 = &foo;
> 	fp2 = &bar;
> 
> Now calling foo.print() and bar.print() still take the same overhead as
> a C function call, because the compiler can determine the type of foo
> and bar statically.  Calling fp1->print() and fp2->print() involve
> dynamic lookup, because even though fp1 and fp2 are declared to be
> Foo pointers, they can really point to a Foo or anything derived from
> it. In this example, fp1->print() will call the Foo print function
> and fp2->print() would call the Bar print function.
> 
> This dynamic lookup requires one extra memory reference per call.

But can I define another level:

class Fee : public Bar {
public:

	 void print();

};

and have this function override the one inherited from Bar? My 
understanding of C++ is that this is not true (I could be
wrong, however, as I'm not a guru). I guess I should have called
this "dynamic redefinition" rather than "dynamic lookup".

Also, can I define a virtual function halfway down an inheritance
chain and have it inherited?

Furthermore, your example seems to confirm my assertion that 
"virtual = inherited".

(Apologies to those who are not interested in the esoterica of
object oriented programming. Maybe this discussion should be
moved to comp.lang?)

		Jim Kempf	kempf@hplabs.hp.com

keith@nih-csl.UUCP (keith gorlen) (05/19/87)

In article <1837@hplabsc.UUCP>, kempf@hplabsc.UUCP (Jim Kempf) writes:
> In article <6894@alice.UUCP>, ark@alice.UUCP writes:
> 
> > Second, C++ does have dynamic lookup of methods at run time -- that's
> > what "virtual" is for:
> > 
> > 	class Foo {
> > 	public:
> > 		virtual void print();
> > 	};
> > 
> > 	class Bar: public Foo {
> > 	public:
> > 		void print();
> > 	};
> > 
> > 	Foo foo;
> > 	Bar bar;
> > 	Foo* fp1;
> > 	Foo* fp2;
> > 
> > 	fp1 = &foo;
> > 	fp2 = &bar;
> > 
> > Now calling foo.print() and bar.print() still take the same overhead as
> > a C function call, because the compiler can determine the type of foo
> > and bar statically. ...

In fact, the code generated for foo.print() and bar.print() uses the virtual
function pointer table (vtbl) just as fp1->print() and fp2->print() do.  You
must write Foo::foo.print() to inhibit the dynamic binding.  It is not
immediately obvious to me why this is.

> 
> But can I define another level:
> 
> class Fee : public Bar {
> public:
> 
> 	 void print();
> 
> };
> 
> and have this function override the one inherited from Bar?

Yes.

> Also, can I define a virtual function halfway down an inheritance
> chain and have it inherited?

If by this you mean "If I declare Foo::print() as a non-virtual member
function and Bar::print() as a virtual member function, will class Fee
inherit the definition of Bar::print()?" the answer is yes.

Where the C++ dynamic binding mechanism differs from that of
Smalltalk-80 is that the table used to locate the virtual member
functions ("methods" in Smalltalk parlance) for a class contains only
the methods actually defined in the class in Smalltalk, whereas in C++
the table contains pointers to virtual functions defined in the class
AND to those inherited from the base class, the base class's base
class, etc.  Thus, in Smalltalk calling a method involves searching
the tables from the class of the current object up toward the root of
the class hierarchy until the method is found.  In C++, you just index
into the table for the class of the current object.  C++ trades off
space for speed.  Also, C++ has nothing analogous to Smalltalk's
"super".

> (Apologies to those who are not interested in the esoterica of
> object oriented programming. Maybe this discussion should be
> moved to comp.lang?)

Yes, it should!




Subject: Re: Do every object based systems suffer from poor performance ?
Newsgroups: comp.arch
Keywords: capability, object, 80286, 432
Summary: Clarification of C++ virtual functions
References: <6055@shemp.UCLA.EDU> <1831@hplabsc.UUCP> <6894@alice.UUCP> <1837@hplabsc.UUCP>



-- 
	Keith Gorlen			phone: (301) 496-5363
	Building 12A, Room 2017		uucp: seismo!elsie!nih-csl!keith
	National Institutes of Health
	Bethesda, MD 20892