snippetjavaModerate
Convert IP address to its binary representation
Viewed 0 times
addressconvertitsbinaryrepresentation
Problem
For a recent lab at the university we had to match the longest prefix for an IP (v4) address by using a Trie data structure. The code works fine, but it takes about 2 minutes to load a 14 million-line routing table. I examined what was causing the slowness, and it was the (
For example, the IP address
The speedup of the
```
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
final String ip = "127.0.0.1";
String binaryIp;
final long start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i ++) {
binaryIp = fast(ip);
}
long fast = System.currentTimeMillis();
for (int i = 0; i < 10000000; i ++) {
binaryIp = slow(ip);
}
long slow = System.currentTimeMillis();
System.out.println("Fast time: " + (fast - start) + " ms");
System.out.println("Slow time: " + (slow - fast) + " ms");
}
public static String fast(String ip) {
StringBuilder bStringBuilder = new StringBuilder();
String ipParts[] = ip.split("\\.");
for (String ipPart : ipParts) {
String binString = Integer.toBinaryString(Integer.parseInt(ipPart));
int length = 8 - binString.length();
char[] padArray = new char[length];
Arrays.fill(padArray, '0');
bStringBuilder.append(padArray).append(binString);
}
System.out.println(bStringBuilder.toString());
return bStringBuilder.toString();
}
public static String slow(Strin
String) IP to (String) binary format conversion.For example, the IP address
127.0.0.1 should be converted to 01111111000000000000000000000001. I my original method (slow) uses String.format, which I find much more readable and easy to follow. I then wrote a different method using a temporary char[], filled with '0' to use as padding.The speedup of the
fast method is about 6x. Below is a stripped down version for demonstration and measurement:```
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
final String ip = "127.0.0.1";
String binaryIp;
final long start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i ++) {
binaryIp = fast(ip);
}
long fast = System.currentTimeMillis();
for (int i = 0; i < 10000000; i ++) {
binaryIp = slow(ip);
}
long slow = System.currentTimeMillis();
System.out.println("Fast time: " + (fast - start) + " ms");
System.out.println("Slow time: " + (slow - fast) + " ms");
}
public static String fast(String ip) {
StringBuilder bStringBuilder = new StringBuilder();
String ipParts[] = ip.split("\\.");
for (String ipPart : ipParts) {
String binString = Integer.toBinaryString(Integer.parseInt(ipPart));
int length = 8 - binString.length();
char[] padArray = new char[length];
Arrays.fill(padArray, '0');
bStringBuilder.append(padArray).append(binString);
}
System.out.println(bStringBuilder.toString());
return bStringBuilder.toString();
}
public static String slow(Strin
Solution
I don't have access to your test file, but try:
In general, I'd suggest avoiding hungarian notation (
Note that your performance testing is flawed. The problem is the VM performs internal optimizations as it runs which can improve the performance of the system. You should test either fast or slow, but not both, in one execution. Don't test the same string over and over again, but pull in your routing file. Then, unless your whole application is to run this one method on the file and then stop, you should run for a while, throw out that data, then start measuring. Maybe do 2 executions of the file, but only time the second one. That imitates the method being called from a live system that's been running a while, instead of a cold system.
Two more things: as @rofl said, presize the StringBuilder. Also pull the System.out.println() out of your method - it's an artificial drag on the performance.
-- Working off of @rofl's other suggestion, this is 25% faster on my machine than your
private static final String[] PAD_ZEROS=
new String[] {
"00000000",
"0000000",
"000000",
"00000",
"0000",
"000",
"00",
"0",
""
};
public static String fast(final String ip) {
final StringBuilder result = new StringBuilder();
final String octals[] = ip.split("\\.");
for (final String octal: octals) {
final String binaryString = Integer.toBinaryString(Integer.parseInt(octal));
result.append(PAD_ZEROS[binaryString.length()]);
result.append(binaryString);
}
return result.toString();
}In general, I'd suggest avoiding hungarian notation (
bStringBuilder), unnecessary abbreviations(binString), and magic numbers (if you keep the 8, it should be in a private static final class-level variable).Note that your performance testing is flawed. The problem is the VM performs internal optimizations as it runs which can improve the performance of the system. You should test either fast or slow, but not both, in one execution. Don't test the same string over and over again, but pull in your routing file. Then, unless your whole application is to run this one method on the file and then stop, you should run for a while, throw out that data, then start measuring. Maybe do 2 executions of the file, but only time the second one. That imitates the method being called from a live system that's been running a while, instead of a cold system.
Two more things: as @rofl said, presize the StringBuilder. Also pull the System.out.println() out of your method - it's an artificial drag on the performance.
-- Working off of @rofl's other suggestion, this is 25% faster on my machine than your
fast method, including the time to populate the map. It does consume more memory, and it eagerly maps numbers which may not be used. It is less elegant than @rofl's suggestion, and possibly slower, but I find it easier to read.private static final String[] PAD_ZEROS =
new String[] {
"00000000",
"0000000",
"000000",
"00000",
"0000",
"000",
"00",
"0",
""
};
private static final Map MAP =
new HashMap(256);
private static void populateMap() {
for (int i = 0; i < 256; i++) {
final String binaryString = Integer.toBinaryString(i);
MAP.put(
Integer.toString(i),
PAD_ZEROS[binaryString.length()] + binaryString);
}
}
public static String faster(final String ip) {
final StringBuilder result = new StringBuilder(32);
final String octals[] = ip.split("\\.");
for (final String octal: octals) {
result.append(MAP.get(octal));
}
return result.toString();
}Code Snippets
private static final String[] PAD_ZEROS=
new String[] {
"00000000",
"0000000",
"000000",
"00000",
"0000",
"000",
"00",
"0",
""
};
public static String fast(final String ip) {
final StringBuilder result = new StringBuilder();
final String octals[] = ip.split("\\.");
for (final String octal: octals) {
final String binaryString = Integer.toBinaryString(Integer.parseInt(octal));
result.append(PAD_ZEROS[binaryString.length()]);
result.append(binaryString);
}
return result.toString();
}private static final String[] PAD_ZEROS =
new String[] {
"00000000",
"0000000",
"000000",
"00000",
"0000",
"000",
"00",
"0",
""
};
private static final Map<String, String> MAP =
new HashMap<String, String>(256);
private static void populateMap() {
for (int i = 0; i < 256; i++) {
final String binaryString = Integer.toBinaryString(i);
MAP.put(
Integer.toString(i),
PAD_ZEROS[binaryString.length()] + binaryString);
}
}
public static String faster(final String ip) {
final StringBuilder result = new StringBuilder(32);
final String octals[] = ip.split("\\.");
for (final String octal: octals) {
result.append(MAP.get(octal));
}
return result.toString();
}Context
StackExchange Code Review Q#84376, answer score: 10
Revisions (0)
No revisions yet.