[m-rev.] for review: Use a better algorithm for unwinding version_arrays.
Peter Wang
novalazy at gmail.com
Wed Aug 6 14:27:37 AEST 2014
On Tue, 29 Jul 2014 14:59:53 +1000, Paul Bone <paul at bone.id.au> wrote:
> Use a better algorithm for unwinding version_arrays.
>
> For review by Peter Wang.
>
> Branches: master, version-14_01-branch.
>
> This is an alternative implementation to something I've recently put on the
> release branch. If we beleive that this is better and/or less risky than my
> previous change then it could go onto the release branch too.
>
> ---
>
> The old version_array rewind code used linear stack space in order to
> perform it's updates in the right order (newest to oldest) by following the
> structure's next pointers (which are a oldest to newest list). I previously
> introduced week prev pointers so that walking over this structure newest to
> oldest could be done with constant stack space. However that is less
> efficient than the method suggested by Peter Wang.
>
> Peter suggested using a bitmap and traversing oldest-to-newest, marking
> each update in the bitmap and checking the bitmap before making any update.
> Thus preserving older values over newer ones (which is good, this code
> _rewinds_ updates). This patch implements Peter's suggestion and removes
> the prev pointers from the structure for C and Java backends.
Will you attempt the C# implementation? I think mono has a non-Boehm GC
option which you could try, if that's the problem.
> library/version_array.m:
> As above.
>
> runtime/mercury_bitmap.h:
> Add some macros for initialising bitmaps and testing, setting and clearing
> their bits.
>
> library/bitmap.m:
> java/runtime/MercuryBitmap.java:
> Move the MercuryBitmap class into the runtime library. This makes it
> easier for other standard library modules to use this Java
> class.
>
> tests/hard_coded/version_array_test.exp:
> tests/hard_coded/version_array_test.m:
> Ensure that the test verifies that rolling back updates to a version
> array rolls back changes in the correct order: If two updates modify the
> same cell, then the older one should be visible in the result.
>
> Use longer arrays so that the bitmap used in the rollback code is more
> than one byte in length.
> diff --git a/java/runtime/MercuryBitmap.java b/java/runtime/MercuryBitmap.java
> new file mode 100644
> index 0000000..5a83023
> --- /dev/null
> +++ b/java/runtime/MercuryBitmap.java
> @@ -0,0 +1,83 @@
> +//
> +// Copyright (C) 2001-2002, 2004-2007, 2009-2011 The University of Melbourne
> +// Copyright (C) 2014 The Mercury Team.
> +// This file may only be copied under the terms of the GNU Library General
> +// Public License - see the file COPYING.LIB in the Mercury distribution.
> +//
> +
> +package jmercury.runtime;
> +
> +/**
> + * Simple bitmap implementation.
> + * This bitmap class is mainly used by bitmap.m in the standard library. It
> + * is also used by version_array.m which is why it is part of the
> + * jmercury.runtime package rather than being internal to bitmap.m
> + */
> +public class MercuryBitmap implements java.io.Serializable {
> + public static final int BITS_PER_BYTE = 8;
> + public int num_bits;
> + public byte[] elements;
> +
> + public MercuryBitmap(int numBits) {
> + this.num_bits = numBits;
> + this.elements = new byte[numBits / 8 + (((numBits % 8) != 0) ? 1 : 0)];
> + }
int numBytes = (numBits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
> +
> + public MercuryBitmap(int numBits, byte[] elements) {
> + // This is provided so that foreign code can construct bitmaps from an
> + // existing byte array.
> + this.num_bits = numBits;
> + this.elements = elements;
> + }
This constructor is not used anywhere that I can see. I suggest
deleting it. As it is, it looks like an invitation for users to use the
class directly. In my opinion all of java/runtime is off-limits unless
documented, i.e. we have no obligation to maintain compatibility with
anything in there.
> +
> + @Override
> + public boolean equals(Object that) {
> + if (this == that) {
> + return true;
> + }
> + if (that instanceof MercuryBitmap) {
> + MercuryBitmap other = (MercuryBitmap)that;
> + return this.num_bits == other.num_bits
> + && java.util.Arrays.equals(this.elements, other.elements);
> + }
> + return false;
> + }
> +
> + public byte getByte(int byteno)
> + {
> + return elements[byteno];
> + }
> +
> + public boolean getBit(int bit)
> + {
> + return (getByte(byteIndexForBit(bit))
> + & (1 << bitIndexWithinByte(bit))) != 0;
> + }
> +
> + public void setBit(int bit)
> + {
> + byte b;
> +
> + b = getByte(byteIndexForBit(bit));
> + b |= 1 << bitIndexWithinByte(bit);
> + elements[byteIndexForBit(bit)] = b;
> + }
> +
> + public void clearBit(int bit)
> + {
> + byte b;
> +
> + b = getByte(byteIndexForBit(bit));
> + b &= ~(1 << bitIndexWithinByte(bit));
> + elements[byteIndexForBit(bit)] = b;
> + }
getByte and clearBit have no users so, again, I would delete them.
Up to you.
> +
> + public static int byteIndexForBit(int bit) {
> + return bit / BITS_PER_BYTE;
> + }
> +
> + public static int bitIndexWithinByte(int bit) {
> + return bit % BITS_PER_BYTE;
> + }
> +
> +}
> diff --git a/runtime/mercury_bitmap.h b/runtime/mercury_bitmap.h
> index 64427eb..94f5240 100644
> --- a/runtime/mercury_bitmap.h
> +++ b/runtime/mercury_bitmap.h
> @@ -159,9 +159,42 @@ MR_String MR_bitmap_to_quoted_string_saved_hp(MR_ConstBitmapPtr,
> #define MR_bitmap_length_in_bytes(bits) \
> (((bits) / MR_BITS_PER_BYTE) + (((bits) % MR_BITS_PER_BYTE) != 0))
>
> +#define MR_bitmap_byte_index_for_bit(bit) \
> + ((bit) / MR_BITS_PER_BYTE)
> +#define MR_bitmap_bit_index_within_byte(bit) \
> + ((bit) % MR_BITS_PER_BYTE)
Line up the backslashes.
> +
> +#define MR_bitmap_zero(bitmap) \
> + do { \
> + size_t bytes = MR_bitmap_length_in_bytes((bitmap)->num_bits); \
> + memset((bitmap)->elements, 0, bytes); \
> + } while(0);
Delete semicolons (two more below)
> +#define MR_bitmap_get(bitmap, bit) \
> + (!!(((bitmap)->elements[MR_bitmap_byte_index_for_bit(bit)]) & \
> + (1 << MR_bitmap_bit_index_within_byte(bit))))
MR_bitmap_get_bit ?
> +#define MR_bitmap_set(bitmap, bit) \
> + do { \
> + MR_uint_least8_t byte; \
> + \
> + byte = (bitmap)->elements[MR_bitmap_byte_index_for_bit(bit)]; \
> + byte |= 1 << MR_bitmap_bit_index_within_byte(bit); \
> + (bitmap)->elements[MR_bitmap_byte_index_for_bit(bit)] = byte; \
> + } while (0);
MR_bitmap_set_bit ?
> +#define MR_bitmap_clear(bitmap, bit) \
> + do { \
> + MR_uint_least8_t byte; \
> + \
> + byte = (bitmap)->elements[MR_bitmap_byte_index_for_bit(bit)]; \
> + byte &= ~(1 << MR_bitmap_bit_index_within_byte(bit)); \
> + (bitmap)->elements[MR_bitmap_byte_index_for_bit(bit)] = byte; \
> + } while (0);
MR_bitmap_clear_bit ?
Again, unused.
> /*
> -** void MR_allocate_bitmap_msg(MR_String ptr, size_t bytes,
> -** int bits_in_last_byte, MR_Code *proclabel):
> +** void MR_allocate_bitmap_msg(MR_BitmapPtr ptr, size_t bits,
> +** MR_Code *proclabel):
> ** Allocate enough word aligned memory to hold `bytes' bytes. Also
Please fix this sentence as well.
> ** record for memory profiling purposes the location, proclabel, of the
> ** allocation if profiling is enabled.
I think it would be better to update the C# backend at the same time.
If you can't test it then make a best effort and post an updated patch,
then I can fix any minor compilation problems.
Peter
More information about the reviews
mailing list