Yay! New Ubuntu!

The new 10.10 version of ubuntu is out! So of course the Ubuntu servers are getting hammered. :)

The best thing to do, is to get the cd image from BitTorrent, since a direct download will only get you 80-90kB/s, where my torrent is currently downloading at 300-500kB/s. I really think they ought to advertise the BitTorrent option more prominently, especially since torrents tend to speed up when lots of people are downloading...

Here are all of the torrents, just in case you're interested...

Ubuntu 10.10

Alternate: 32-bit, 64-bit

Desktop: 32-bit, 64-bit

Server: 32-bit, 64-bit

Kubuntu 10.10

Alternate CD: 32-bit, 64-bit

Desktop CD: 32-bit, 64-bit

Desktop DVD: 32-bit, 64-bit

Xubuntu 10.10

Alternate: 32-bit, 64-bit

Desktop: 32-bit, 64-bit

Edubuntu 10.10

DVD: 32-bit, 64-bit

So there you go. Enjoy, and be sure to pay it forward by seeding plenty. :)

Memory Allocators

So, it's been over a month since my last (tiny) post, so I thought I'd do a good update on my current workings.

Coding-wise, I'm working on a game with my g/f for the Android. Progress is going slow, since I have this one stubborn bug that I can't seem to find the cause to. It's a really annoying bug, where a call to free() is failing. I know for a fact that the memory address is valid, since I can access it correctly right before the call, and I've looked at every free() that preceded this one, so I know this isn't some random double-free error. I'm just completely baffled. For now, I've simply commented out the free() call, so I can test other portions of the app. But that one naggy line of code is driving me nuts. (I'm starting to see the appeal of Java's garbage collector, now...) :X

Non-coding-wise, however, things have been going much, much worse. You see, I am, sadly, a terminally boring person. :) As such, I like to study things that don't interest many other people, and this week has been a prime example. Taking a slight cue from my programming problems mentioned above, I've been studying memory allocators.

Memory allocators are the things that actually power C/C++'s dynamic memory capabilities through function calls like malloc(), realloc(), and free(). I, for some god-awful reason, find these libraries fascinating! I've always wondered how they actually work, and now seemed like as good a time as any to start, so I dived right in.

First of all, I looked into dlmalloc. When it comes to malloc implementations, dlmalloc (which stands for Doug Lea's Malloc) is pretty much the de-facto standard of single-threaded allocators. It's fast, simple, uses little memory, can usually avoid severe fragmentation, and is released into the public domain. Android uses a stock version of dlmalloc in their 'Bionic' libc, and glibc uses a heavily modified version of dlmalloc called ptmalloc. (A version that has been modified to handle multi-threading better.)

The way dlmalloc works is moderately simple. The memory from the OS is obtained with a call to sbrk(), and is organized into 'Segments' of contiguous memory, which are stored in a linked-list. This memory is then partitioned up into 'Chunks' which can be marked as either 'free' or 'in-use', where the in-use Chunks have been provided to the user based on a malloc() call (or similar), and the free Chunks are... well... free. :)

Those 'free' Chunks are treated differently based on their size. Small Chunks are stored in a double-linked list for quick access. Malloc() will then try to pick chunks that are next to other small chunks that were recently allocated. (Hopefully improving cache performance.) Larger Chunks are stored in a trie, which is bit-wise keyed based on the size of the chunk. Chunks with the same size in this trie are linked together in a linked list, and sorted in FIFO order. That way, malloc() can find the best fitting chunk quickly. (A lookup should take O(B) time, where B=the number of bits in a pointer.)

... And that's pretty much it.

Of course dlmalloc uses all kinds of clever tricks, like using mmap() for the REALLY big allocations, using /dev/urandom to secure the data from heap-based overflows with random keys, or storing most metadata inside of the freed space, resulting in a fairly small overhead, but those are mostly implementation details. What is really surprising is just how effective these (relatively) simple algorithms are. Sure, over the years, the code has definitely been polished to a mirror-shine. (Some portions have different implementations based on what compiler is being used, for example.) But ultimately, at a high-level, this is a fairly straight-forward malloc(), and it's no wonder why dlmalloc is put to so much use.

There is another interesting malloc implementation out there, and this one is from FreeBSD-land. jemalloc (for Jason Evans' malloc) is the latest allocator used in FreeBSD, and was actually brought into Firefox several years ago, to fix some memory fragmentation problems that were giving the illusion of huge memory leaks.

jemalloc was designed with scalable multithreading in mind, and uses the concept of an 'arena' to do this. An arena is basically a section of the available space that will be used for allocations. Different threads will stick to different arenas, so memory allocated by one thread will tend to be stored in the same memory range as other allocations from that thread, which should improve cache performance. Now, if jemalloc is running on a single-cpu system, then it'll only make one arena and will try to operate similarly to other allocators. However, on systems with multiple cpu's, it will create 4 arenas per processor.

Now, what does jemalloc do to keep track of the actual allocations? Well, that depends on the size of the allocation. Allocations get classified as either Small (with subcategories of Tiny, Quantum-spaced, and Sub-page), Large, and Huge. Based on what category each allocation falls under, the amount of memory being asked for is rounded up to certain strategic values, to make sure that they fit together well. Then, different strategies are employed for all of the different chunk-size categories. (I won't get into the mucky details of this, because it's fairly tedious, but I will note that they do employ red-black trees. :) )

jemalloc has been shown to be an incredibly efficient malloc when it comes to multi-core systems. jemalloc's white paper has figures that show it beating dlmalloc in pretty much anything with more than one thread, which makes sense, given that dlmalloc's idea of multithreading support is one single lock that makes sure that dlmalloc is only being called from one thread at a time. (Can you say: "bottleneck"? :) ) However, dlmalloc still beats jemalloc in single-threaded applications. (But they're pretty darn close.)

Both of these allocators do fairly well, but fragmentation will always be an issue. Thus far, there is no allocator that can perfectly prevent fragmentation, and thanks to how C/C++ handles things, you can't write a memory defragmentor. Since the programmer has access to the raw pointers in both C and C++, he/she can hide those pointers in any number of ways. The best a C/C++ memory defragmenter could do is perform an exhaustive search of the program's memory. Not only would this be incredibly slow, but it would also be very wrong. What if the program stored a pointer to some position in the middle of the allocated memory? Those have to be updated as well, so that means we have to be searching for a potentially huge range of values. Or what if the program has an integer that JUST HAPPENS to have the same value as that pointer? Then, since memory is un-typed, there is no way to tell that integer apart from a pointer, and it will be altered, potentially causing seemingly random crashes, or even worse, errant behaviour.

I guess this would be a big plus for some of those other languages, like C# or Java, which just hide pointers from the programmer. Allocators for those languages could arbitrarily move data for defragmentation purposes, and need only make sure they document their changes. Plus, these languages come with garbage collectors, and so that's nice too. :)

Of course, defragmentation isn't the cure-all for everything. Defrag-ing is going to be slow, and the allocators used in Java and C# still take some cues from the standard allocators, like dlmalloc, ptmalloc, or jemalloc, and it only makes sense. All of those normal allocators try to set things up so that a defragmenter would rarely be neccessary, so, given that we only defag when things really go south, we could be fairly certain that the defragmenter would rarely be used. Then, the program would only really see the practical benefits of a nice, orderly heap. :)

(Alternatively, we could just have an incremental defragmenter, and just move one or two chunks every time we malloc(), or free() something...)

Well, that's pretty much what I've been up to recently. I hope I didn't bore anyone who was brave enough to read through all of that... I don't want to bore any of my 2 loyal readers. ;)

Anyway, now for some sleep, cause I really want to get a good start on that level editor tomorrow... :)

All kind of resources:

PS: On an unrelated note: Defensio is absolutely amazing. It has caught 100% of all spam thus far, with no false positives! Cool! :D

Defensio Spam Checking

Yesterday, I read this post on DtD's Blog. For the last few months, I've been getting around 20-25 spam posts per day. That is a lot, especially for a small blog like this. Taking DtD's lead, I think I'll upgrade my spam defenses as well.

The packaged spam checker in Habari only detects around 5% of those spam messages, so I switched to the Defensio spam detection system. Here's to hoping that it works, because digging through page after page of comments like "free c1al1s" and "Hi, I'm new here, check out these links" is starting to get REALLY old.

Getting Tilt Data on an Android Phone

I haven't posted in a while, so I thought I'd post a little bit of code that I wrote for an android phone app that I'm working on. You see, Google recently deprecated one of the older ways of getting tilt data from the Android OS, but they didn't really document the new way of doing it. Plus, most resources I found online still use the old method, so I wrote a class to get the tilt data in an easy-to-use manner. (And without using any deprecated functions.)

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;

public class TiltCalc {

private boolean needsRecalc = false;
private float[] tilt_data = {0, 0, 0}, gravity = {0, 0, 0}, magnet = {0, 0, 0};

// Change this to make the sensors respond quicker, or slower:
private static final int delay = SensorManager.SENSOR_DELAY_GAME;


// Special class used to handle sensor events:
private final SensorEventListener listen = new SensorEventListener() {
public void onSensorChanged(SensorEvent e) {
final float[] vals = e.values, target;

// Just capture the Gyroscope data, if it exists:
//if(e.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
// System.arraycopy(vals, 0, tilt_data, 0, 3);
// return;
//}

// Else, we'll capture the data, and mark the class for a re-calc:
target = (e.sensor.getType() == Sensor.TYPE_ACCELEROMETER) ? gravity : magnet;
needsRecalc = true;
System.arraycopy(vals, 0, target, 0, 3);
}

public void onAccuracyChanged(Sensor event, int res) {}
};

// The constructor will use a context object to register itself for various inputs:
public TiltCalc(Context c) {
SensorManager man = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);

Sensor mag_sensor = man.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
Sensor acc_sensor = man.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//Sensor gyr_sensor = man.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

// Turns out Android's gyroscope doesn't work this way, so it's been disabled for now...
//if(man.registerListener(listen, gyr_sensor, delay)) {
// Log.d("TiltCalc", "Gyroscope detected, and successfully connected.");

// Use an accelerometer+compass approach:
//} else
if( man.registerListener(listen, mag_sensor, delay) &&
man.registerListener(listen, acc_sensor, delay) ) {
Log.d("TiltCalc", "No gyroscope, falling back on accelerometer+compass.");

} else {
Log.d("TiltCalc", "No acceptable hardware found.");

// We will remove the listener, just in case one of the accelerometer sensors
// registered, just not the other one:
man.unregisterListener(listen);
}
}

// Will return the most up-to-date tilt data in the vals[] array
public void getTilt(float[] vals) {

// If some of the data has been changed, then we need to recalculate some things...
if(needsRecalc) {
float[] R={0,0,0,0,0,0,0,0,0};

// Calculate the rotation matrix, and use that to get the orientation:
if(SensorManager.getRotationMatrix(R, null, gravity, magnet))
SensorManager.getOrientation(R, tilt_data);

needsRecalc = false;
}

System.arraycopy(tilt_data, 0, vals, 0, 3);
}
}

The constructor needs a context object, so that it can register itself for sensor updates. The easiest way to do this is to call the function in the main activity, using 'this' as the context. (Activity is a subclass of Context...)

Then, you would just call getTilt(float[] vals) to get the 3 tilt values. That function will return the 3 tilt values into the float[] that is passed into the class. The tilt values will be setup like:

Diagram showing the tilt axes

So vals[0] is rotating the phone around like a compass, vals[1] is tilting the phone up and down, and vals[2] is tilting the phone left and right.

This class is coded so that if you have an accurate gyroscope in the phone, the class will use that to get the tilt data. However, in most cases, you won't have a gyroscope, so the class will fall back on a less accurate (but still perfectly usable) accelerometer + compass method of calculating tilt.

Note: I do not have a phone with a gyroscope, so that code is ENTIRELY untested. Plus, since Google didn't document the output format of gyroscope updates, this code is based on the very bold assumption that Google wouldn't give tilt data in differing formats based on the data's source. (EDIT: Turns out this *WAS* a very bold assumption... :P)

Anyway, this code is public domain, so have fun. :)

EDIT (19 Jan 2011): Now that there are Android phones with gyroscopes, we know that they don't work in the way I was expecting, so the gyroscope code has been commented out. I'll update the code again once I know for sure how they work...

California Elections

Just a quick post today. I just got back from voting in the California Primary Election, and I was excited to see that I was voter #256 in the roster. (Like, the 256th alphabetical voter in the list.) I was fairly excited about that. :)

Also, the polling place was in my old middle school, and I was sad to see that they had all the same computers. I went to that school in year 1999, and the computers were a few years old THEN. Those computers are technically from 2 decades ago... :/

Plus, the nice librarian who worked at the school when I was a student there, was still working there, but she's retiring in 2 days, and this is the last election that she'll be administering over. :(

So, I'm voter #256, my school needs a bigger tech budget, and the librarian is retiring in 2 days. All in all, this has been an interesting day, and I've only been awake for an hour or two. ;)

← Previous  1 2 3 4 5 … 13 Next →

About

User