I got this question in an interview the other day and would like to know some best possible answers(I did not answer very well haha):
Scenario: There is a webpage that is monitoring the bytes sent over a some network. Every time a byte is sent the recordByte() function is called passing that byte, this could happen hundred of thousands of times per day. There is a button on this page that when pressed displays the last 100 bytes passed to recordByte() on screen (it does this by calling the print method below).
The following code is what I was given and asked to fill out:
public class networkTraffic {
public void recordByte(Byte b){
}
public String print() {
}
}
What is the best way to store the 100 bytes? A list? Curious how best to do this.
Something like this (circular buffer) :
byte[] buffer = new byte[100];
int index = 0;
public void recordByte(Byte b) {
index = (index + 1) % 100;
buffer[index] = b;
}
public void print() {
for(int i = index; i < index + 100; i++) {
System.out.print(buffer[i % 100]);
}
}
The benefits of using a circular buffer:
You can reserve the space statically. In a real-time network application (VoIP, streaming,..)this is often done because you don't need to store all data of a transmission, but only a window containing the new bytes to be processed.
It's fast: can be implemented with an array with read and write cost of O(1).
I don't know java, but there must be a queue concept whereby you would enqueue bytes until the number of items in the queue reached 100, at which point you would dequeue one byte and then enqueue another.
public void recordByte(Byte b)
{
if (queue.ItemCount >= 100)
{
queue.dequeue();
}
queue.enqueue(b);
}
You could print by peeking at the items:
public String print()
{
foreach (Byte b in queue)
{
print("X", b); // some hexadecimal print function
}
}
Circular Buffer using array:
Array of 100 bytes
Keep track of where the head index is i
For recordByte() put the current byte in A[i] and i = i+1 % 100;
For print(), return subarray(i+1, 100) concatenate with subarray(0, i)
Queue using linked list (or the java Queue):
For recordByte() add new byte to the end
If the new length to be more than 100, remove the first element
For print() simply print the list
Here is my code. It might look a bit obscure, but I am pretty sure this is the fastest way to do it (at least it would be in C++, not so sure about Java):
public class networkTraffic {
public networkTraffic() {
_ary = new byte[100];
_idx = _ary.length;
}
public void recordByte(Byte b){
_ary[--_idx] = b;
if (_idx == 0) {
_idx = _ary.length;
}
}
private int _idx;
private byte[] _ary;
}
Some points to note:
No data is allocated/deallocated when calling recordByte().
I did not use %, because it is slower than a direct comparison and using the if (branch prediction might help here too)
--_idx is faster than _idx-- because no temporary variable is involved.
I count backwards to 0, because then I do not have to get _ary.length each time in the call, but only every 100 times when the first entry is reached. Maybe this is not necessary, the compiler could take care of it.
if there were less than 100 calls to recordByte(), the rest is zeroes.
Easiest thing is to shove it in an array. The max size that the array can accommodate is 100 bytes. Keep adding bytes as they are streaming off the web. After the first 100 bytes are in the array, when the 101st byte comes, remove the byte at the head (i.e. 0th). Keep doing this. This is basically a queue. FIFO concept. Ater the download is done, you are left with the last 100 bytes.
Not just after the download but at any given point in time, this array will have the last 100 bytes.
#Yottagray Not getting where the problem is? There seems to be a number of generic approaches (array, circular array etc) & a number of language specific approaches (byteArray etc). Am I missing something?
Multithreaded solution with non-blocking I/O:
private static final int N = 100;
private volatile byte[] buffer1 = new byte[N];
private volatile byte[] buffer2 = new byte[N];
private volatile int index = -1;
private volatile int tag;
synchronized public void recordByte(byte b) {
index++;
if (index == N * 2) {
//both buffers are full
buffer1 = buffer2;
buffer2 = new byte[N];
index = N;
}
if (index < N) {
buffer1[index] = b;
} else {
buffer2[index - N] = b;
}
}
public void print() {
byte[] localBuffer1, localBuffer2;
int localIndex, localTag;
synchronized (this) {
localBuffer1 = buffer1;
localBuffer2 = buffer2;
localIndex = index;
localTag = tag++;
}
int buffer1Start = localIndex - N >= 0 ? localIndex - N + 1 : 0;
int buffer1End = localIndex < N ? localIndex : N - 1;
printSlice(localBuffer1, buffer1Start, buffer1End, localTag);
if (localIndex >= N) {
printSlice(localBuffer2, 0, localIndex - N, localTag);
}
}
private void printSlice(byte[] buffer, int start, int end, int tag) {
for(int i = start; i <= end; i++) {
System.out.println(tag + ": "+ buffer[i]);
}
}
Just for the heck of it. How about using an ArrayList<Byte>? Say why not?
public class networkTraffic {
static ArrayList<Byte> networkMonitor; // ArrayList<Byte> reference
static { networkMonitor = new ArrayList<Byte>(100); } // Static Initialization Block
public void recordByte(Byte b){
networkMonitor.add(b);
while(networkMonitor.size() > 100){
networkMonitor.remove(0);
}
}
public void print() {
for (int i = 0; i < networkMonitor.size(); i++) {
System.out.println(networkMonitor.get(i));
}
// if(networkMonitor.size() < 100){
// for(int i = networkMonitor.size(); i < 100; i++){
// System.out.println("Emtpy byte");
// }
// }
}
}
Related
For a high performance blocked bloom filter, I would like to align data to cache lines. (I know it's easier to do such tricks in C, but I would like to use Java.)
I do have a solution, but I'm not sure if it's correct, or if there is a better way. My solution tries to find the start of the cache line using the following algorithm:
for each possible offset o (0..63; I assume cache line length of 64)
start a thread that reads from data[o] and writes that to data[o + 8]
in the main thread, write '1' to data[o], and wait until that ends up in data[o + 8] (so wait for the other thread)
repeat that
Then, measure how fast this was, basically how many increments for a loop of 1 million (in each thread). My logic is, it is slower if the data is in a different cache line.
Here my code:
public static void main(String... args) {
for(int i=0; i<20; i++) {
int size = (int) (1000 + Math.random() * 1000);
byte[] data = new byte[size];
int cacheLineOffset = getCacheLineOffset(data);
System.out.println("offset: " + cacheLineOffset);
}
}
private static int getCacheLineOffset(byte[] data) {
for (int i = 0; i < 10; i++) {
int x = tryGetCacheLineOffset(data, i + 3);
if (x != -1) {
return x;
}
}
System.out.println("Cache line start not found");
return 0;
}
private static int tryGetCacheLineOffset(byte[] data, int testCount) {
// assume synchronization between two threads is faster(?)
// if each thread works on the same cache line
int[] counters = new int[64];
int testOffset = 8;
for (int test = 0; test < testCount; test++) {
for (int offset = 0; offset < 64; offset++) {
final int o = offset;
final Semaphore sema = new Semaphore(0);
Thread t = new Thread() {
public void run() {
try {
sema.acquire();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
for (int i = 0; i < 1000000; i++) {
data[o + testOffset] = data[o];
}
}
};
t.start();
sema.release();
data[o] = 1;
int counter = 0;
byte waitfor = 1;
for (int i = 0; i < 1000000; i++) {
byte x = data[o + testOffset];
if (x == waitfor) {
data[o]++;
counter++;
waitfor++;
}
}
try {
t.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
counters[offset] += counter;
}
}
Arrays.fill(data, 0, testOffset + 64, (byte) 0);
int low = Integer.MAX_VALUE, high = Integer.MIN_VALUE;
for (int i = 0; i < 64; i++) {
// average of 3
int avg3 = (counters[(i - 1 + 64) % 64] + counters[i] + counters[(i + 1) % 64]) / 3;
low = Math.min(low, avg3);
high = Math.max(high, avg3);
}
if (low * 1.1 > high) {
// no significant difference between low and high
return -1;
}
int lowCount = 0;
boolean[] isLow = new boolean[64];
for (int i = 0; i < 64; i++) {
if (counters[i] < (low + high) / 2) {
isLow[i] = true;
lowCount++;
}
}
if (lowCount != 8) {
// unclear
return -1;
}
for (int i = 0; i < 64; i++) {
if (isLow[(i - 1 + 64) % 64] && !isLow[i]) {
return i;
}
}
return -1;
}
It prints (example):
offset: 16
offset: 24
offset: 0
offset: 40
offset: 40
offset: 8
offset: 24
offset: 40
...
So arrays in Java seems to be aligned to 8 bytes.
You know that the GC can move objects... so your perfectly aligned array may get misaligned later.
I'd try ByteBuffer; I guess, a direct one gets aligned a lot (to a page boundary).
Unsafe can give you the address and with JNI, you can get an array pinned.
First things first - everything in java is 8 bytes aligned, not arrays only. There's a tool for that Java Object Layout, that you can play with. Small-ish thing here (unrelated, but related) - in java-9 String(s) internally are stored as byte[] to shrink their space for LATIN-1 ones, because everything is 8-bytes aligned there was an addition of a field coder (byte) without making any instance of the string bigger - there was a gap big enough to fit that byte.
Your entire idea that objects that are aligned will be faster to access is right. That is much much more visible when multiple threads try to access that data, also known as false-sharing (but I bet you knew that). Btw here, there are methods in Unsafe that will show you object addresses, but since GC can move these around, this becomes useless for your requirement.
You would not be the first one that tries to overcome this. Unfortunately if you read that blog entry - you will see that even very experienced developers (which I admire) fail at this. A VM is notoriously smart to remove checks and code that you might think is needed somewhere, especially when JIT C2 kicks in.
What you are really looking for is:
jdk.internal.vm.annotation.Contended
annotation. This is the only way that will guarantee cache line alignment. If you really want to read about all other "tricks" that could be done, than Alekesy Shipilev's examples are the ones you are looking for.
This program takes integers from user input and puts them in a collection. It then prints the positive values first, then the negative values, and doesn't print repeated numbers. It stops asking for input once the user enters 0. Here is the code:
public class Intcoll2
{
private int[] c;
private int[] d;
private int howmany = 0;
public Intcoll2()
{
c = new int[500];
}
public Intcoll2(int i)
{
c = new int[i]
}
public void insert(int i)
{
if (i > 0)
{
int j = 0;
while ((j <= howmany) && (c[j] != i)) j++;
if (j == howmany)
{
if (j == c.length - 1)
{
d = new int[2*c.length];
for (int k = 0; k<c.length; i++){
d[k] = c[k];
}
c = d;
}
c[j] = i; c[j + 1] = 0;
}
howmany++;
}
}
public int get_howmany()
{
int j=0, howmany=0;
while (c[j]!=0) {howmany++; j++;}
return howmany;
}
Now my current print method looks like this:
public void print()
{
int j = 0;
System.out.println();
while (j <= howmany)
{
System.out.println(c[j]); j++;
}
}
But when I try to use that in my client, it only prints out zeros. Any help with what I'm doing wrong would be greatly appreciated.
An answer that you were probably not looking for, but still on the only real answer you should care about.
Your problem is not that somewhere in that code a bug is hiding. The problem is that your code is confusing beyond limits:
Dont use single-character variable names.
The constructor that takes an int ... creates an empty array!
Dont say "collection" when you are using arrays.
Dont give fields and local variables the same name.
Seriously: understanding this mess is mainly complicated and hard because you wrote code that is hard to read.
Now you are asking other people to debug such complicated code that you (the author who created it!) do not understand in the first place.
Instead, you might throw this whole thing away. And slowly write it again; but in a way that isn't at all confusing to the reader.
I took a look at your class and rewrote it in a more legible manner. I didn't test it but I'm confident it works. You can check it out and hopefully understand what's happening. Hope this helps!
public class IntCollection2 {
private int[] collection; // A large allocation, not neccessarily filled up.
private int currentSize; // The number of spots currently filled in the collection.
public IntCollection2() {
collection = new int[500];
currentSize = 0;
}
public IntCollection2(int size) {
collection = new int[size];
currentSize = 0;
}
/**
* Inserts a new element into the internal array. If the current array is filled up,
* a new array double the size of the current one is allocated.
* #param element An int to insert into the collection. Must not be '0'.
* #return True if the element was successfully inserted, false if the element was
* equal to '0' and was ignored.
*/
public boolean insert(int element) {
if (element != 0) {
if (currentSize < collection.length - 1) {
collection[currentSize] = element;
} else {
int[] newCollection = new int[collection.length * 2];
for (int i = 0; i < currentSize; i++) {
newCollection[i] = collection[i];
}
newCollection[currentSize] = element;
collection = newCollection;
}
currentSize++;
return true;
} else {
return false;
}
}
/**
* Not actually necessary because the class automatically updates its currentSize
* every time a new element is inserted.
* #return The current number of filled spots in the internal array.
*/
public int getCurrentSize() {
int size = 0;
for (int i = 0; i < collection.length && collection[i] != 0; i++) {
size++;
}
return size;
}
/**
* Prints out all the elements currently in the collection, one on each line.
*/
public void print() {
System.out.println();
for (int i = 0; i < currentSize; i++) {
System.out.println(collection[i]);
}
}
}
FYI: this class just prints out every element in the collection, in order. You mentioned something about printing positive then negative values, but I leave that to you.
EDIT: I'm guessing you're brand new to programming, so I just want to clarify exactly what a collection is. An array is an ordered list of elements. When you create an array, the computer sets aside a bit of memory to hold exactly the number of elements you told it to. You cannot change the size of an existing array. A collection is basically a wrapper around an array. It makes a bigger array than it needs to hold its elements, and when its array becomes full, it allocates a new, bigger one that can hold more elements.
I need to load around 2MB of data quickly on startup of my Android application.
I really need all this data in memory, so something like SQLite etc. is not an alternative.
The data consists of about 3000 int[][] arrays. The array dimension is around [7][7] on average.
I first implemented some prototype on my desktop, and ported it to android. On the desktop, I simply used Java's (de)serialization. Deserialization of that data takes about 90ms on my desktop computer.
However on Android 2.2.1 the same process takes about 15seconds(!) on my HTC Magic. It's so slow that if I don't to the deserialization in a seperate thred, my app will be killed. All in all, this is unacceptably slow.
What am I doing wrong? Should I
switch to something like protocol buffers? Would that really speed up the process of deserialization of several magnitudes - after all, it's not complex objects that I am deserializing, just int[][] arrays?!
design my own custom binary file format? I've never done that before, and no clue where to start
do something else?
Why not bypass the built-in deserialization, and use direct binary I/O?
When speed is your primary concern, not necessarily ease of programming, you can't beat it.
For output the pseudo-code would look like this:
write number of arrays
for each array
write n,m array sizes
for each element of array
write array element
For input, the pseudo-code would be:
read number of arrays
for each array
read n,m array sizes
allocate the array
for each element of array
read array element
When you read/write numbers in binary, you bypass all the conversion between binary and characters.
The speed should be limited only by the data transfer rate of the file storage media.
after trying out several things, as Mike Dunlavey suggested, direct binary I/O seemed fastest. I almost verbatim used his sketched out version. For completeness however, and if someone else wants to try, I'll post my full code here; even though it's very basic and without any kind of sanity check. This is for reading such a binary stream; writing is absolutely analogous.
import java.io.*;
public static int[][][] readBinaryInt(String filename) throws IOException {
DataInputStream in = new DataInputStream(
new BufferedInputStream(new FileInputStream(filename)));
int dimOfData = in.readInt();
int[][][] patternijk = new int[dimofData][][];
for(int i=0;i<dimofData;i++) {
int dimStrokes = in.readInt();
int[][] patternjk = new int[dimStrokes][];
for(int j=0;j<dimStrokes;j++) {
int dimPoints = in.readInt();
int[] patternk = new int[dimPoints];
for(int k=0;k<dimPoints;k++) {
patternk[k] = in.readInt();
}
patternjk[j] = patternk;
}
patternijk[i] = patternjk;
}
in.close();
return patternijk;
}
I had the same kind of issues on a project some months ago. I think you should split your file in various parts, and only load relevant parts following a choice from the user for example.
Hope it will be helpful!
I dont know your data but if you optimize your loop, it will effect the deserialize time unbelievably.
if you look at example below
computeRecursively(30);
computeRecursivelyWithLoop(30); // 270 milisecond
computeIteratively(30); // 1 milisecond
computeRecursivelyFasterUsingBigInteger(30); // about twice s fast as before version
computeRecursivelyFasterUsingBigIntegerAllocations(50000); // only 1.3 Second !!!
public class Fibo {
public static void main(String[] args) {
// try the methods
}
public static long computeRecursively(int n) {
if (n > 1) {
System.out.println(computeRecursively(n - 2)
+ computeRecursively(n - 1));
return computeRecursively(n - 2) + computeRecursively(n - 1);
}
return n;
}
public static long computeRecursivelyWithLoop(int n) {
if (n > 1) {
long result = 1;
do {
result += computeRecursivelyWithLoop(n - 2);
n--;
} while (n > 1);
System.out.println(result);
return result;
}
return n;
}
public static long computeIteratively(int n) {
if (n > 1) {
long a = 0, b = 1;
do {
long tmp = b;
b += a;
a = tmp;
System.out.println(a);
} while (--n > 1);
System.out.println(b);
return b;
}
return n;
}
public static BigInteger computeRecursivelyFasterUsingBigInteger(int n) {
if (n > 1) {
int m = (n / 2) + (n & 1); // not obvious at first – wouldn’t it be
// great to have a better comment here?
BigInteger fM = computeRecursivelyFasterUsingBigInteger(m);
BigInteger fM_1 = computeRecursivelyFasterUsingBigInteger(m - 1);
if ((n & 1) == 1) {
// F(m)^2 + F(m-1)^2
System.out.println(fM.pow(2).add(fM_1.pow(2)));
return fM.pow(2).add(fM_1.pow(2)); // three BigInteger objects
// created
} else {
// (2*F(m-1) + F(m)) * F(m)
System.out.println( fM_1.shiftLeft(1).add(fM).multiply(fM));
return fM_1.shiftLeft(1).add(fM).multiply(fM); // three
// BigInteger
// objects
// created
}
}
return (n == 0) ? BigInteger.ZERO : BigInteger.ONE; // no BigInteger
// object created
}
public static long computeRecursivelyFasterUsingBigIntegerAllocations(int n) {
long allocations = 0;
if (n > 1) {
int m = (n / 2) + (n & 1);
allocations += computeRecursivelyFasterUsingBigIntegerAllocations(m);
allocations += computeRecursivelyFasterUsingBigIntegerAllocations(m - 1);
// 3 more BigInteger objects allocated
allocations += 3;
System.out.println(allocations);
}
return allocations; // approximate number of BigInteger objects
// allocated when
// computeRecursivelyFasterUsingBigInteger(n) is
// called
}
}
I'm writing a program which creates a large number of large arrays to store data. All of this data has to held in RAM, so I'm avoiding objects and currently using shorts to save space. These shorts serve as ID numbers which can be put into a lookup class to get the corresponding object on demand. I have recently questioned whether I'll need the whole 2 bytes of a short, and so I'm now wondering if there's anyway to define the data type being stored in one place in my code so that I can change it easily without having to hunt down every cast, return type, etc. that is currently set to short.
If I were willing to use objects I could easily just do
class MySmallNumber extends Short{}
and change the parent class if necessary.
If this were C/C++, i could use
#define small short
for the effect I'm looking for.
I'm searching for a way to do something like this in java that won't require storing 64-bit object references in my arrays. Any help is greatly appreciated. Right now I'm looking at a really messy IDE replace all in order to do this.
You can incapsulate you array in some custom class. It shouldn't add considerable space overhead because you work with large arrays.
In all other places in your code you can use long. When you pass these longs to you array custom class you can convert it to the one you use inside it.
Finally you have to make changes in this one class only.
I would suggest factoring out all code that depends on the type of your ID values into a separate class. Let that class handle all the operations (including lookup) that depend on whether the ID values are short, byte, or something else. You can pass individual values in and out as short or even int values, even if internally they are converted to byte. (This is, for instance, how java.io.DataOutputStream.writeByte(int) was written—it takes an int argument and treats it as a byte value.)
not quite sure what you are after here, but this may be of interest:
import java.util.Arrays;
interface Index {
short getIndex(int i);
void setIndex(int i, short value);
int size();
}
class ShortIndexImpl implements Index {
ShortIndexImpl(int n) {
indices = new short[n];
}
#Override public short getIndex(int i) {
return indices[i];
}
#Override public void setIndex(int i, short value) {
indices[i] = value;
}
#Override public int size() {
return indices.length;
}
final short[] indices;
}
class TenBitIndexImpl implements Index {
TenBitIndexImpl(int n) {
indices = new int[(n + 2) / 3];
}
#Override public short getIndex(int i) {
int index = i / 3;
int remainder = i % 3;
int word = indices[index];
return (short) (0x3ff & (word >> shifts[remainder]));
}
#Override public void setIndex(int i, short value) {
int index = i / 3;
int remainder = i % 3;
int word = indices[index] & ~masks[remainder];
int shiftedValue = ((int) value) << shifts[remainder];
word |= shiftedValue;
indices[index] = word;
}
#Override public int size() {
return indices.length;
}
final int masks[] = new int[] { 0x3ff00000, 0xffc00, 0x3ff };
final int shifts[] = new int[] { 20, 10, 0 };
final int[] indices;
}
public class Main {
static void test(Index index) {
for (int i = 0; i < values.length; i++)
index.setIndex(i, values[i]);
for (int i = 0; i < values.length; i++) {
System.out.println(values[i] + " " + index.getIndex(i));
if (index.getIndex(i) != values[i])
System.out.println("expected " + values[i] + " but got " + index.getIndex(i));
}
}
public static void main(String[] args) {
Index index = new ShortIndexImpl(values.length);
test(index);
index = new TenBitIndexImpl(values.length);
test(index);
System.out.println("indices");
for (int i = 0; i < ((TenBitIndexImpl) index).indices.length; i++)
System.out.println(((TenBitIndexImpl) index).indices[i]);
}
static short[] values = new short[] { 1, 2, 3, 4, 5, 6 };
}
I'm writing a program that is supposed to create chains of numbers and see witch one is the longest. The problem is that I run out of memory and I have no idea what eats all of the memory. Does anyone know were the problem is?
public static void main(String[] args) {
ArrayList<Integer> longestchain;
ArrayList<Integer> chain = new ArrayList<Integer>();
int size = 0;
int longestsize = 0;
int start;
int number = 0;
for(int i = 3; i < 1000000; i++)
{
start = i;
chain.clear();
chain.add(start);
size = 1;
while(true)
{
if(start == 1)
{
break;
}
if(iseven(start))
{
start = start / 2;
}
else
{
start = start*3 + 1;
}
chain.add(start);
size++;
}
if(size > longestsize)
{
longestsize = size;
longestchain = chain;
number = i;
}
//System.out.println(i);
}
System.out.println(number + ". " + longestsize);
}
public static boolean iseven(int n)
{
return (n % 2 == 0);
}
The problem is that when i=113383 you're running into an integer overflow. This results in an infinite loop that keeps adding to chain until you run out of heap space. Change chain and longestchain to ArrayList<Long>, start to long and iseven() to take long, and you'll solve that particular problem.
Another problem is that longestchain = chain assigns the reference, whereas you need to copy the contents. Otherwise the next iteration will wipe longestchain.
This will probably not be the solution, but a hint:
The default array size for an ArrayList is 10. Initialize your ArrayLists to a value closer to what you are expecting, or many array creations happen under the hood:
// e.g.
ArrayList<Integer> chain = new ArrayList<Integer>(50000);
Don't know why are you running out of memory, but I noticed a bug in your code - longestchain and chain point to the same object, so when you clear chain, you also clear longestchain. You can fix it by creating a new array with contents of chain instead of an assignment.