All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.openhft.chronicle.algo.MemoryUnit Maven / Gradle / Ivy

There is a newer version: 2.27ea0
Show newest version
/*
 *     Copyright (C) 2015  higherfrequencytrading.com
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with this program.  If not, see .
 */

/*
 * Based on java.util.concurrent.TimeUnit, which is
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

package net.openhft.chronicle.algo;

import java.util.concurrent.TimeUnit;

/**
 * A {@code MemoryUnit} represents memory amounts at a given unit of
 * granularity and provides utility methods to convert across units.  A
 * {@code MemoryUnit} does not maintain memory information, but only
 * helps organize and use memory amounts representations that may be maintained
 * separately across various contexts.
 *
 * 

Note than in this class kilo-, mega- and giga- prefixes means 2^10 = 1024 multiplexing, * that is more common in low-level programming, CPU and operation system contexts, * not 1000 as defined by International System of Units (SI). * *

A {@code MemoryUnit} is mainly used to inform memory amount-based methods * how a given memory amount parameter should be interpreted. * *

API of {@code MemoryUnit} is copied from {@link TimeUnit} enum. */ public enum MemoryUnit { /** * Memory unit representing one bit. */ BITS { @Override public long toBits(long a) { return a; } @Override public long toBytes(long a) { return a/(C1/C0); } @Override public long toLongs(long a) { return a/(C2/C0); } @Override public long toCacheLines(long a) { return a/(C3/C0); } @Override public long toKilobytes(long a) { return a/(C4/C0); } @Override public long toPages(long a) { return a/(C5/C0); } @Override public long toMegabytes(long a) { return a/(C6/C0); } @Override public long toGigabytes(long a) { return a/(C7/C0); } @Override public long convert(long a, MemoryUnit u) { return u.toBits(a); } @Override long alignToBytes(long a) { return y(a, C1/C0); } @Override long alignToLongs(long a) { return y(a, C2/C0); } @Override long alignToCacheLines(long a) { return y(a, C3/C0); } @Override long alignToKilobytes(long a) { return y(a, C4/C0); } @Override long alignToPages(long a) { return y(a, C5/C0); } @Override long alignToMegabytes(long a) { return y(a, C6/C0); } @Override long alignToGigabytes(long a) { return y(a, C7/C0); } @Override public long align(long a, MemoryUnit u) { return ise(u, this); } }, /** * Memory unit representing one byte, i. e. 8 bits. */ BYTES { @Override public long toBits(long a) { return x(a, C1/C0, MAX/(C1/C0)); } @Override public long toBytes(long a) { return a; } @Override public long toLongs(long a) { return a/(C2/C1); } @Override public long toCacheLines(long a) { return a/(C3/C1); } @Override public long toKilobytes(long a) { return a/(C4/C1); } @Override public long toPages(long a) { return a/(C5/C1); } @Override public long toMegabytes(long a) { return a/(C6/C1); } @Override public long toGigabytes(long a) { return a/(C7/C1); } @Override public long convert(long a, MemoryUnit u) { return u.toBytes(a); } @Override long alignToBytes(long a) { return ise(this, BYTES); } @Override long alignToLongs(long a) { return y(a, C2/C1); } @Override long alignToCacheLines(long a) { return y(a, C3/C1); } @Override long alignToKilobytes(long a) { return y(a, C4/C1); } @Override long alignToPages(long a) { return y(a, C5/C1); } @Override long alignToMegabytes(long a) { return y(a, C6/C1); } @Override long alignToGigabytes(long a) { return y(a, C7/C1); } @Override public long align(long a, MemoryUnit u) { return u.alignToBytes(a); } }, /** * Memory unit representing 8 bytes, i. e. 64-bit word, * the width of Java's primitive {@code long} type. */ LONGS { @Override public long toBits(long a) { return x(a, C2/C0, MAX/(C2/C0)); } @Override public long toBytes(long a) { return x(a, C2/C1, MAX/(C2/C1)); } @Override public long toLongs(long a) { return a; } @Override public long toCacheLines(long a) { return a/(C3/C2); } @Override public long toKilobytes(long a) { return a/(C4/C2); } @Override public long toPages(long a) { return a/(C5/C2); } @Override public long toMegabytes(long a) { return a/(C6/C2); } @Override public long toGigabytes(long a) { return a/(C7/C2); } @Override public long convert(long a, MemoryUnit u) { return u.toLongs(a); } @Override long alignToBytes(long a) { return ise(this, BYTES); } @Override long alignToLongs(long a) { return ise(this, LONGS); } @Override long alignToCacheLines(long a) { return y(a, C3/C2); } @Override long alignToKilobytes(long a) { return y(a, C4/C2); } @Override long alignToPages(long a) { return y(a, C5/C2); } @Override long alignToMegabytes(long a) { return y(a, C6/C2); } @Override long alignToGigabytes(long a) { return y(a, C7/C2); } @Override public long align(long a, MemoryUnit u) { return u.alignToLongs(a); } }, /** * Memory unit representing 64 bytes, i. e. the most common CPU cache line size. */ CACHE_LINES { @Override public long toBits(long a) { return x(a, C3/C0, MAX/(C3/C0)); } @Override public long toBytes(long a) { return x(a, C3/C1, MAX/(C3/C1)); } @Override public long toLongs(long a) { return x(a, C3/C2, MAX/(C3/C2)); } @Override public long toCacheLines(long a) { return a; } @Override public long toKilobytes(long a) { return a/(C4/C3); } @Override public long toPages(long a) { return a/(C5/C3); } @Override public long toMegabytes(long a) { return a/(C6/C3); } @Override public long toGigabytes(long a) { return a/(C7/C3); } @Override public long convert(long a, MemoryUnit u) { return u.toCacheLines(a); } @Override long alignToBytes(long a) { return ise(this, BYTES); } @Override long alignToLongs(long a) { return ise(this, LONGS); } @Override long alignToCacheLines(long a) { return ise(this, CACHE_LINES); } @Override long alignToKilobytes(long a) { return y(a, C4/C3); } @Override long alignToPages(long a) { return y(a, C5/C3); } @Override long alignToMegabytes(long a) { return y(a, C6/C3); } @Override long alignToGigabytes(long a) { return y(a, C7/C3); } @Override public long align(long a, MemoryUnit u) { return u.alignToCacheLines(a); } }, /** * Memory unit representing 1024 bytes. */ KILOBYTES { @Override public long toBits(long a) { return x(a, C4/C0, MAX/(C4/C0)); } @Override public long toBytes(long a) { return x(a, C4/C1, MAX/(C4/C1)); } @Override public long toLongs(long a) { return x(a, C4/C2, MAX/(C4/C2)); } @Override public long toCacheLines(long a) { return x(a, C4/C3, MAX/(C4/C3)); } @Override public long toKilobytes(long a) { return a; } @Override public long toPages(long a) { return a/(C5/C4); } @Override public long toMegabytes(long a) { return a/(C6/C4); } @Override public long toGigabytes(long a) { return a/(C7/C4); } @Override public long convert(long a, MemoryUnit u) { return u.toKilobytes(a); } @Override long alignToBytes(long a) { return ise(this, BYTES); } @Override long alignToLongs(long a) { return ise(this, LONGS); } @Override long alignToCacheLines(long a) { return ise(this, CACHE_LINES); } @Override long alignToKilobytes(long a) { return ise(this, KILOBYTES); } @Override long alignToPages(long a) { return y(a, C5/C4); } @Override long alignToMegabytes(long a) { return y(a, C6/C4); } @Override long alignToGigabytes(long a) { return y(a, C7/C4); } @Override public long align(long a, MemoryUnit u) { return u.alignToKilobytes(a); } }, /** * Memory unit representing 4096 bytes, i. e. the most common native memory page size. */ PAGES { @Override public long toBits(long a) { return x(a, C5/C0, MAX/(C5/C0)); } @Override public long toBytes(long a) { return x(a, C5/C1, MAX/(C5/C1)); } @Override public long toLongs(long a) { return x(a, C5/C2, MAX/(C5/C2)); } @Override public long toCacheLines(long a) { return x(a, C5/C3, MAX/(C5/C3)); } @Override public long toKilobytes(long a) { return x(a, C5/C4, MAX/(C5/C4)); } @Override public long toPages(long a) { return a; } @Override public long toMegabytes(long a) { return a/(C6/C5); } @Override public long toGigabytes(long a) { return a/(C7/C5); } @Override public long convert(long a, MemoryUnit u) { return u.toPages(a); } @Override long alignToBytes(long a) { return ise(this, BYTES); } @Override long alignToLongs(long a) { return ise(this, LONGS); } @Override long alignToCacheLines(long a) { return ise(this, CACHE_LINES); } @Override long alignToKilobytes(long a) { return ise(this, KILOBYTES); } @Override long alignToPages(long a) { return ise(this, PAGES); } @Override long alignToMegabytes(long a) { return y(a, C6/C5); } @Override long alignToGigabytes(long a) { return y(a, C7/C5); } @Override public long align(long a, MemoryUnit u) { return u.alignToPages(a); } }, /** * Memory unit representing 1024 kilobytes. */ MEGABYTES { @Override public long toBits(long a) { return x(a, C6/C0, MAX/(C6/C0)); } @Override public long toBytes(long a) { return x(a, C6/C1, MAX/(C6/C1)); } @Override public long toLongs(long a) { return x(a, C6/C2, MAX/(C6/C2)); } @Override public long toCacheLines(long a) { return x(a, C6/C3, MAX/(C6/C3)); } @Override public long toKilobytes(long a) { return x(a, C6/C4, MAX/(C6/C4)); } @Override public long toPages(long a) { return x(a, C6/C5, MAX/(C6/C5)); } @Override public long toMegabytes(long a) { return a; } @Override public long toGigabytes(long a) { return a/(C7/C6); } @Override public long convert(long a, MemoryUnit u) { return u.toMegabytes(a); } @Override long alignToBytes(long a) { return ise(this, BYTES); } @Override long alignToLongs(long a) { return ise(this, LONGS); } @Override long alignToCacheLines(long a) { return ise(this, CACHE_LINES); } @Override long alignToKilobytes(long a) { return ise(this, KILOBYTES); } @Override long alignToPages(long a) { return ise(this, PAGES); } @Override long alignToMegabytes(long a) { return ise(this, MEGABYTES); } @Override long alignToGigabytes(long a) { return y(a, C7/C6); } @Override public long align(long a, MemoryUnit u) { return u.alignToMegabytes(a); } }, /** * Memory unit representing 1024 megabytes. */ GIGABYTES { @Override public long toBits(long a) { return x(a, C7/C0, MAX/(C7/C0)); } @Override public long toBytes(long a) { return x(a, C7/C1, MAX/(C7/C1)); } @Override public long toLongs(long a) { return x(a, C7/C2, MAX/(C7/C2)); } @Override public long toCacheLines(long a) { return x(a, C7/C3, MAX/(C7/C3)); } @Override public long toKilobytes(long a) { return x(a, C7/C4, MAX/(C7/C4)); } @Override public long toPages(long a) { return x(a, C7/C5, MAX/(C7/C5)); } @Override public long toMegabytes(long a) { return x(a, C7/C6, MAX/(C7/C6)); } @Override public long toGigabytes(long a) { return a; } @Override public long convert(long a, MemoryUnit u) { return u.toGigabytes(a); } @Override long alignToBytes(long a) { return ise(this, BYTES); } @Override long alignToLongs(long a) { return ise(this, LONGS); } @Override long alignToCacheLines(long a) { return ise(this, CACHE_LINES); } @Override long alignToKilobytes(long a) { return ise(this, KILOBYTES); } @Override long alignToPages(long a) { return ise(this, PAGES); } @Override long alignToMegabytes(long a) { return ise(this, MEGABYTES); } @Override long alignToGigabytes(long a) { return ise(this, GIGABYTES); } @Override public long align(long a, MemoryUnit u) { return u.alignToGigabytes(a); } }; // Handy constants for conversion methods static final long C0 = 1L; static final long C1 = C0 * 8L; static final long C2 = C1 * 8L; static final long C3 = C2 * 8L; static final long C4 = C3 * 16L; static final long C5 = C4 * 4L; static final long C6 = C5 * 256L; static final long C7 = C6 * 1024L; static final long MAX = Long.MAX_VALUE; /** * Scale d by m, checking for overflow. * This has a short name to make above code more readable. */ static long x(long a, long m, long over) { if (a > over) return Long.MAX_VALUE; if (a < -over) return Long.MIN_VALUE; return a * m; } static long y(long amount, long align) { if (amount == 0L) return 0L; long mask = ~(align - 1L); if (amount > 0L) { long filled = amount + align - 1L; if (filled > 0L) { return filled & mask; } else { long maxAlignedLong = Long.MAX_VALUE & mask; if (amount <= maxAlignedLong) return maxAlignedLong; } } else { // amount is negative long filled = amount - align + 1L; if (filled < 0L) { return filled & mask; } else { long minAlignedLong = Long.MIN_VALUE & mask; if (amount >= minAlignedLong) return minAlignedLong; } } throw new IllegalArgumentException("Couldn't align " + amount + " by " + align); } static long ise(MemoryUnit unitToAlign, MemoryUnit alignmentUnit) { throw new IllegalStateException("Couldn't align " + unitToAlign + " by " + alignmentUnit); } // To maintain full signature compatibility with 1.5, and to improve the // clarity of the generated javadoc (see 6287639: Abstract methods in // enum classes should not be listed as abstract), method convert // etc. are not declared abstract but otherwise act as abstract methods. /** * Converts the given memory amount in the given unit to this unit. * Conversions from finer to coarser granularities truncate, so * lose precision. For example, converting {@code 7} bits * to bytes results in {@code 0}. Conversions from coarser to * finer granularities with arguments that would numerically * overflow saturate to {@code Long.MIN_VALUE} if negative or * {@code Long.MAX_VALUE} if positive. * *

For example, to convert 4096 bytes to cache lines, use: * {@code MemoryUnit.CACHE_LINES.convert(4096L, MemoryUnit.BYTES)} * * @param sourceAmount the memory amount in the given {@code sourceUnit} * @param sourceUnit the unit of the {@code sourceAmount} argument * @return the converted amount in this unit, * or {@code Long.MIN_VALUE} if conversion would negatively * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. */ public long convert(long sourceAmount, MemoryUnit sourceUnit) { throw new AbstractMethodError(); } /** * Aligns the given memory amount in the given unit to this unit. For example, aligning * {@code 1000} bytes to kilobytes results in {@code 1024}. Negative values are aligned towards * negative infinity: e. g. aligning {@code -5} longs to cache lines results in {@code -8}. * * @param amountToAlign the memory amount in the given {@code unit} * @param unit the unit of the {@code amountToAlign} argument * @return the aligned amount, still in the given unit * @throws IllegalArgumentException if the given {@code unit} is finer than this unit, * or if the aligned value overflows {@code long} bounds */ public long align(long amountToAlign, MemoryUnit unit) { throw new AbstractMethodError(); } /** * Equivalent to {@code convert(align(sourceAmount, sourceUnit), sourceUnit)}. * * @param sourceAmount the memory amount in the given {@code sourceUnit} * @param sourceUnit the unit of the {@code sourceAmount} argument * @return the saturated converted amount in this unit * @throws IllegalArgumentException if the given {@code sourceUnit} is finer than this unit, * or if the aligned value overflows {@code long} bounds */ public long alignAndConvert(long sourceAmount, MemoryUnit sourceUnit) { return convert(align(sourceAmount, sourceUnit), sourceUnit); } /** * Equivalent to * {@link #convert(long, MemoryUnit) BITS.convert(amount, this)}. * @param amount the amount * @return the converted amount, * or {@code Long.MIN_VALUE} if conversion would negatively * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. */ public long toBits(long amount) { throw new AbstractMethodError(); } /** * Equivalent to * {@link #convert(long, MemoryUnit) BYTES.convert(amount, this)}. * @param amount the amount * @return the converted amount, * or {@code Long.MIN_VALUE} if conversion would negatively * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. */ public long toBytes(long amount) { throw new AbstractMethodError(); } /** * Equivalent to * {@link #convert(long, MemoryUnit) LONGS.convert(amount, this)}. * @param amount the amount * @return the converted amount, * or {@code Long.MIN_VALUE} if conversion would negatively * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. */ public long toLongs(long amount) { throw new AbstractMethodError(); } /** * Equivalent to * {@link #convert(long, MemoryUnit) CACHE_LINES.convert(amount, this)}. * @param amount the amount * @return the converted amount, * or {@code Long.MIN_VALUE} if conversion would negatively * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. */ public long toCacheLines(long amount) { throw new AbstractMethodError(); } /** * Equivalent to * {@link #convert(long, MemoryUnit) KILOBYTES.convert(amount, this)}. * @param amount the amount * @return the converted amount, * or {@code Long.MIN_VALUE} if conversion would negatively * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. */ public long toKilobytes(long amount) { throw new AbstractMethodError(); } /** * Equivalent to * {@link #convert(long, MemoryUnit) PAGES.convert(amount, this)}. * @param amount the amount * @return the converted amount, * or {@code Long.MIN_VALUE} if conversion would negatively * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. */ public long toPages(long amount) { throw new AbstractMethodError(); } /** * Equivalent to * {@link #convert(long, MemoryUnit) MEGABYTES.convert(amount, this)}. * @param amount the amount * @return the converted amount, * or {@code Long.MIN_VALUE} if conversion would negatively * overflow, or {@code Long.MAX_VALUE} if it would positively overflow. */ public long toMegabytes(long amount) { throw new AbstractMethodError(); } /** * Equivalent to * {@link #convert(long, MemoryUnit) GIGABYTES.convert(amount, this)}. * @param amount the amount * @return the converted amount */ public long toGigabytes(long amount) { throw new AbstractMethodError(); } abstract long alignToBytes(long amount); abstract long alignToLongs(long amount); abstract long alignToCacheLines(long amount); abstract long alignToKilobytes(long amount); abstract long alignToPages(long amount); abstract long alignToMegabytes(long amount); abstract long alignToGigabytes(long amount); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy