Table of Contents
BEDEPOT.COM NEW PRODUCTS: AutoFolder Launcher, BeMyCheckbook, Scheduler, Squeezer New BeOS Products now available on BeDepot.com: AutoFolder Launcher by Thunder Munchkin Software BeMyCheckbook by Thunder Munchkin Software Scheduler by Brian Tietz Squeezer by Intuiware
BE ENGINEERING INSIGHTS: The Hidden Cost of Things By Pierre Raynaud-Richard pierre@be.com "Be creates software platforms that enable rich media and web experiences on personal computers and Internet appliances." You've probably seen statements similar to this many times during the last few months. In engineering terms, the last two words -- "Internet appliances" -- imply a new and significant constraint: memory footprint. This is because many Internet appliances have no hard disk. Rather, they have only a small, compact flash, usually with an IDE interface, and only a limited amount of memory. Typically, this means 16-32MB of main memory, and 8-16MB of storage space, at least for devices trying to be much more than a cellular phone, text-based Web browser. As you can imagine, swap space isn't even an option with devices such as these. One consequence is that, more than ever, you need to be careful about memory usage. Unfortunately, this is often difficult to measure, since things can be shared by multiple teams or hidden by VM or heap fragmentation. Also, there are two types of memory allocation: visible and hidden. Visible memory allocation stores user data (like the buffer of a Bitmap, the messages of a MessageQueue, the points of a Polygon, and so on). Hidden memory allocation is used by BeOS objects and components themselves, so you don't really know what's there. And that's what this article is about -- measuring the memory footprint of empty objects, or how much does it cost to set up a mechanism even before sending any data through it... But enough talk, here are the numbers (tested under R4.5): <less than 16 bytes range> VM maps each 4KB page using a 4 byte value. For very large areas, a second word may also be allocated for virtual page info (some are preallocated at boot time). <16 to 32 bytes range> <32 to 64 bytes range> <64 to 128 bytes range> <128 to 256 bytes range> <256 to 512 bytes range> <1KB to 2KB range> <16KB and more...> Remember, these numbers don't include whatever memory will be used by the objects once you start using them (and that can be a lot, depending on what you do). And remember too, "smaller is always better."
BE ENGINEERING INSIGHTS: Building Interdependent Shared Libraries By Marc Ferguson marc@be.com
If you've ever ported a large UNIX application to BeOS you may have run into the problem of building shared library versions of a set of interdependent static libraries. One way to do this is to build a shareable file for each library that contains only the exported symbols of that library. The symbol files can be used to link the other shared libraries in the set. Here is a bash script that automates the process. It takes a list of ".a" files and builds a corresponding ".so" file for each one. The only thing missing from this listing is the extract_symbols function, which is described later. TMP_DIR=/tmp/so-builder.$$ GCC_ARGS=-nostart ARCHIVES= SYMBOLS= while [ $# != 0 ] do case "$1" in -*) GCC_ARGS="$GCC_ARGS $1";; /*.a) ARCHIVES="$ARCHIVES $1";; *.a) ARCHIVES="$ARCHIVES 'pwd'/$1";; *) GCC_ARGS="$GCC_ARGS $1";; esac shift done rm -rf $TMP_DIR mkdir $TMP_DIR pushd $TMP_DIR for arch in $ARCHIVES; do tail=${arch##*/} base=${tail%.a} extract_symbols $arch >$base.s soname="-Xlinker -soname=$base.so" echo gcc -nostdlib $soname -o $base.syms $base.s gcc -nostdlib $soname -o $base.syms $base.s SYMBOLS="$SYMBOLS $base.syms" done for arch in $ARCHIVES; do ar x $arch echo gcc $GCC_ARGS -o ${arch%.a}.so *.o $SYMBOLS gcc $GCC_ARGS -o ${arch%.a}.so *.o $SYMBOLS rm -f *.o done popd rm -rf $TMP_DIR The "while" loop scans the shell arguments, putting an absolute path to each ".a" file in $ARCHIVES. The rest of the arguments are passed to the gcc command which builds the ".so" files. In a temporary directory, the first "for" loop builds a symbol file for each archive by compiling the result of the extract_symbols function. The "-soname" argument to the linker provides the name of the ".so" file in which the symbols will ultimately be found. The second "for" loop relinks each archive into a shared library using the symbol files just created. The extract_symbols function takes an archive and creates an assembler file which contains only symbols. One way to do that is to use a sed script on the output of nm: extract_symbols () { nm $1 | sed -n ' s/^[0-9a-f]* T \(..*\)/\ .text\ .globl \1\ \1:/p s/^[0-9a-f]* D \(..*\)/\ .data\ .globl \1\ .size \1,4\ \1:/p s/^[0-9a-f]* C \(..*\)/\ .comm \1,4,4/p' } This sed script should take care of most of the symbols you come across, but you may have to tweak it for unusual cases.
DEVELOPERS' WORKSHOP: Of Pointers, Constructors, and Conversions By Owen Smith orpheus@be.com
In this week's installment I intend to put a certain small function in the Be API to rest. Although it was created with the best of intentions, there are several subtle problems with its use, so we're deprecating it. By describing these problems in detail, I hope to illustrate some of the pitfalls of C++ syntax that may be haunting your code. Our victim for solemn interment today is BMessage::BMessage(BMessage*). Now, ever since the good old days, this function has lurked in the shadow of its more hygienic partner, the standard BMessage copy constructor: BMessage::BMessage(const BMessage&). Recall that the copy constructor is called in either of the following two cases: BMessage a; BMessage b(a); // copy constructor specified explicitly BMessage c = a; // also calls the copy constructor, // NOT operator=() ! This works, looks nice, and is the C++ Approved Way of Doing Things. So why have a redundant variant that takes a BMessage* instead of a const BMessage&? In a word, sloth. Consider the following code that uses the copy constructor: MyHandler::MessageReceived(BMessage* msg) { BMessage tmpMsg(*msg); // do something with tmpMsg } With BMessage(BMessage*) we could get away with this: MyHandler::MessageReceived(BMessage* msg) { BMessage tmpMsg(msg); // do something with tmpMsg } As you can see, by using the BMessage(BMessage*) constructor, instead of the widely acclaimed copy constructor, we get one really minimal gain -- we save an asterisk. (Note that dereferencing the pointer here and taking a reference does not incur a performance penalty, as the compiler can easily optimize it.) Nevertheless, since much of the Be API centers around passing pointers to BMessages around, it seems the most natural way to express the copying of one message to another. So, its use is pandemic in both our code and -- I suspect -- in many of your apps as well. Now, where are the subtle problems I spoke of? First, there is the question of constness. Since copying a BMessage does not alter the BMessage, we should be able to pass a const BMessage* into the constructor. Sadly, though, we overlooked this in the initial implementation of the BMessage API, and we can't fix it because of backwards compatibility issues. So if you have a const BMessage, you have to work around this bug in the API by casting away the constness of your BMessage: const BMessage* a; BMessage b(const_cast<BMessage*>(a)); The C++-style cast I've used here looks ugly for a reason: a const_cast is a potentially dangerous operation, and should not be invoked carelessly. Because you're bypassing the compiler's enforcement of constness, you have to blindly trust our claim that the BMessage constructor doesn't modify the original message. Because the regular BMessage copy constructor handles const correctly, it's much easier to use in this case. Secondly, there are a couple of cases where a subtle error in your code will result in an unwanted side effect which is difficult to debug. First, there is the following code:
In this case, I forgot to type an asterisk, and would hope that the compiler would catch the error. But not only does this code compile, it seems to run fine! Why does this compile? It compiles because initialization invokes the copy constructor:
There are two undesirable results of this code:
If this wasn't bad enough, things get even worse. There is also the possibility of unwanted implicit conversions. As a quick review of implicit conversions, recall that a constructor with a single argument defines an implicit conversion from the argument type to the class type. For example, you can define a conversion from a double to a complex number in the following manner: struct Complex { Complex(double aReal) : real(aReal), imag(0.0) {} double real; double imag; }; Then, you can write the following: double mag(Complex c) { return sqrt(c.real*c.real + c.imag*c.imag); } double a; double aMag = mag(a); because the double will automatically be converted into a Complex object for you. Let's say we have the following function which takes a reference to BMessage and modifies the message: void FillMessage(BMessage& msg) { msg.AddString("password", "metatron"); } But when we use this function, we forget that it takes a reference, and we pass it a pointer instead: BMessage* myMsg = new BMessage; FillMessage(myMsg); Again, this is probably a simple typo in your code, and you'd want this code to refuse to compile. But before the compiler rejects this code, it will look for some way to turn your BMessage* into a BMessage&. It can't do this directly, but it can turn a BMessage* into a BMessage, and then it can create a reference to a BMessage from this resulting object. This would be the same as writing: BMessage* myMsg = new BMessage; FillMessage(BMessage(myMsg)); So, the code will compile and run with nary a complaint. The subtle and dangerous problem with this conversion, as the latter piece of code illustrates, is that you are creating a reference to a temporarily constructed BMessage, NOT the original message itself. FillMessage ends up modifying a temporary BMessage that gets thrown away, and the original message is left untouched. This is almost certainly not what you want! Both this problem and the memory leak could be solved by declaring the constructor to be explicit. With the proper constness declared, this would look something like: class BMessage { public: explicit BMessage(const BMessage*); ... }; This prevents the constructor from being used in implicit conversions and initialization -- you have to call the constructor explicitly. However, between these issues, the const issue, and redundancy, we chose to deprecate this constructor instead. So, what does this mean for your code? Well, the code you've already compiled that uses BMessage(BMessage*) will still work in future releases of the BeOS like it currently does -- this is called binary compatibility. However, in future releases we are likely to make BMessage(BMessage*) private. When this happens, your code will no longer compile. So, when you get the chance, take a moment or two to go through your code and change references to BMessage(BMessage*) to BMessage(const BMessage&), and you'll be set.
With a Name Like Be... By Jean-Louis Gassée
We're bound to run into questions, some teasing, and the odd bit of trouble. One question I'm often asked is how the name came to Be. (I forgot to mention feeble puns in the preceding list.) When Steve Sakoman and I started the company, I wanted to call it UT, as in the music note the Latin conjunction... and as in United Technoids. Steve was his usual diplomatic self, not voicing such thoughts as "here we go again." Instead, he offered to investigate other options by looking through the dictionary with his kids over the weekend. The following Monday, I called Steve from the road. How did it go? We stopped at "be," he said. The letter "b," I asked? No, "to be," he replied. And that was it. We looked for conflicting names and, to our surprise, found none we thought might be troublesome. I fired up MacDraw II and typed the two letters of the logo in 72-pt. Times Roman. The spacing between the "B" and the "e" looked awful. However, by typing each letter as a separate object and using the left cursor key, I was able to arrange the letters just so, and we had our first logo. As for name conflicts, we'd been a little too sanguine. One company, Better Education, used its initials publicly. We visited them and reached an amicable arrangement. We'd chosen Be Labs for our legal name, because it sounded good to us. Bell Labs agreed that it sounded good; in fact, they thought it sounded too close to their former, prestigious name. We deferred, particularly since we didn't want a misunderstanding at a time when we were working with AT&T's Hobbit microprocessor. So Be Incorporated became our legal name and we kept Be for our logo and "common" name. Naturally, we want to protect the value of our name, of our brand. This is a lot easier with a name like Exxon or Hewlett-Packard than with a word as common as "Be." If you call your windows replacement business Better Windows, chances are the Redmond company will leave you alone. But if you start a Windows management software company, or, worse, a Windows management utility business, calling it Better Windows could get you into trouble. Apple, for example, has had no end of trouble dealing with the use of "Mac" in the names of products, services, magazines, newsletters, stores... Popularity is not a bad problem to have though, and on a smaller scale, we see good news in the occasional problematic use of our name. (Osborne has no such trouble.) Recently, we came to an amiable arrangement with BeComputing. The name was obviously meant to indicate support of the Be platform, but there was a problem with the perception it could create. BeDepot is part of Be, Inc., but what about BeComputing? In fact, it's not affiliated with us. Fortunately, Eric Schlissel, the CEO of BeComputing, understood our concern. That is, confusion, in one way or another, lowers the value of the brand. This, in turn, hurts everyone associated with the platform -- probably what sages mean when they speak of "brand equity." BeComputing will rename itself Geek Teknologies. We appreciate their understanding of our efforts as well as their support of the Be platform. And now, off to Comdex.
1997 Be Newsletters | 1995 & 1996 Be Newsletters Copyright © 1999 by Be, Inc. All rights reserved. Legal information (includes icon usage info). Comments, questions, or confessions about our site? Please write the Webmaster. |