Hi all,

Sorry for the cross-posting, the 64 bit discussion should probably be migrated to hackers but since it started in users, I post this message in both.

Here is a small explanation of how I see the way to a 64 bit build. There is quite a lot of coding work but also some design decisions that could be discussed on the hackers mailing-list.

If anyone wants to take the challenge, I'll be glad to help or discuss specific points but unfortunately, I don't currently have much time to spend on the emulator. Certainly not enough to do the 64 bit porting myself.

Cheers,
Yves

Porting Mozart to 64 bits architectures
=======================================
First a choice has to be made as to what level of cross-architecture usage we want to achieve.
The three natural choices are:
1. Oz source only. The same Oz code can be executed on both architecture.
2. Pickle level. The pickle format is identical on both architectures, functors compiled on one architecture can be run on the other. 3. Distribution level. A distributed application can be made by sharing entities on two sites running on emulators compiled for different architectures. This implies 2 as the distribution messages re-use the pickle format.

Currently we have distribution level comptatibility between all (32-bit) platforms, regardless of processor type, endianess, etc. so this would seem reasonable to try to achieve the same level of compatibility for differing bit-width.

Then a choice has to be made as to what level of knowledge/usage we want to give to the emulator. 1. Compile-time only. We add -m32 where needed in the Makefiles and adjust the dependencies and build-dependencies of the packages so that they can build easily on 64-bit platforms but as 32 bits executables. 2. Pointers only. Every integer that is actually a pointer in disguise is made to be platform-length. Every other integer is forced to 32 bits. This allows to compile as native 64 bit, gcc can use 64 bits instructions and registers but nothing user-visible is changed, including maximum heap size, etc. 4. Everything. For every integer, the decision is made to make it platform length, fixed to 32 bits (should be uncommon) or fixed to 64 bits. The decision is taken purely on conceptual grounds, based on the meaning of the integer. Every integer that appears in an external format (pickle or distributin message) should be fixed width if we want interoperability. Most others should be platform sized. Some may be pushed to 64 bits even on 32 bits platforms to increase the limits for datastructures (bytestrings lengths, tuple widths, etc.) at the cost of some performance on 32 bits platforms. The range of FDs and FSs could be increased, etc. In short, nothing in the code is decided because of the 32 bit legacy. It could even go as far as considering 64 bit the main platform with some workarounds so that it can continue to work on 32 bits platforms. 3. Between 2 and 4. Like in 4, every integer is considered and a similar decision is made. However, if the amount of work to make it platform sized or fixed to 64 bits is too big compared to the benefits, we fix it to 32 bits as in 2. It might not be very useful to have bytestrings of more than 4Gb or tuples with millions of millions of fields but there have been reports of people hitting the maximum heap size by dealing with enormous number of entities; increasing the range of small (optimized) integers can probably improve performances a lot; some other limits may be easy enough to remove that we wouldn't want to not do so. However, the evaluation of the trade-offs is ultimately in the hands of the one doing the implementation work.

Level 1 should be considered because it is probably rather easy and could be a stop-gap measure while changes are made for another level. Level 2 has probably too high a cost for not much benefit. I would go for level 3, taking advantages where easy enough.

Mozart was designed at a time where 32-bits seemed more than enough for the foreseeable future and excluded from the start 16-bits platforms. Therefore, no attempts were made to avoid or limit dependencies on the bit-width of the platform. The following parts of Mozart are probably the most critical for 64-bit porting.

The memory manager. Mozart manages it's memory in order to implement it's own GC. By necessity, this involves lots of pointers as integers manipulations. Alignments of memory blocks may need to be increased in certain cases.

The tagged pointers. A tagged pointer is a combination of a pointer and a small integer (2-3 bits depending on places), put in the low-order bits of the pointer as they are guaranteed to be zero by alignment. The small integer identifies the type of the pointed-to value. In certain cases (small integers) the "pointer" is not a pointer but the value itself (shifted a few bits). Replacing tagged pointers with something cleaner (e.g. a pair of a type and a union pointer/int) could be done but could increase memory usage 4-fold. By their nature, tagged pointers involve lots of bit-level manipulation of pointers and therefore casting to and-from integers. Most tag manipulations is encapsulated in macros but I wouldn't bet they all are.

The threaded code. Mozart bytecode is loaded in an optimized threaded code format. Some indexes in array are explicitly multiplied by the member size to transform a shift-then-add in a simple add at machine-code level. Instructions sizes are used in many places (at least emulation, GC, pickling) and may need to be adjusted depending on what are their parameters. Alignments requirements may also be a concern. All in all, this part of the code has been very micro-optimized and can contain lots of problematic hacks.

The FD implementation. This is also very old, micro-optimized code that can contain anything... Keeping that part as close as possible to 32 bits would be easiest but because of tagged pointers used for small integers (that would now be pointer-sized), some changes may be needed.

The pickling system. Non-DAG datastructures are pickled using numbered coreferences. What to do when the number of such gets over what can be fit in a 32-bit integer ? Changing the pickle format could be an option but we would then need to change the implementation on the 32-bits side. Other fields may have similar problems.

The way I would go to do the porting is as follow:

1. Remove all the x86 assembly language. It's optimized for old CPUs that nobody uses anymore, compilers have improved a lot, we don't need them since Mozart run on other architectures. 2. Reveres-engineer the functionning of the critical parts above from the source, removing dead code and cruft before fixing them to 64-bit cleanness. 3. Look at remaining compiler warnings for dangerous casts, grep for idioms that need fixing found previously.
4. Test, debug, fix. Lather, rinse, repeat.
_________________________________________________________________________________
mozart-users mailing list                               
[email protected]
http://www.mozart-oz.org/mailman/listinfo/mozart-users

Reply via email to