Monday, June 15, 2020

Base64 of image good or bad

Inspiration of this article is because of a problem we faced while doing Indeed XML generation
from job requisitions in our system. I have tried to compile the knowledge from different 
articles and sources to have a relevant information.
Its a wide spread perception of "optimizing" your images by encoding them to Base64 and including that 
straight into your HTML.
In this post, I want to address why in this day and age, this is almost always a very bad idea that has been carried 
over from years ago. Back then, web browsers had heavy limits on the number of concurrent connections they 
could send to the server. This meant an image heavy website would need to queue up requests and wait for the 
ones before to finish. Base64 provided a way of working around that by using an already open HTTP connection 
to deliver images embedded directly into the HTML or CSS. This effectively removed the need for an extra 
roundtrip the browser would need for each of the files.
With the introduction of multiplexing that arrived with HTTP/2, web browsers have become incredibly efficient
 in delivering hundreds of files through a single connection. This works around most limits that the Base64 
encoding solved and in fact means Base64 now does more bad than good.
To get to the answer why, we first need to establish what Base64 actually is. To put it simply, Base64 is an 
encoding schema used for representing binary data in a text format. This is useful when the storage or delivery
 medium does not support binary data such as when embedding an image into a database, CSS files or HTML.
 One must be careful to not mix up compression with encoding. While compression actually compresses data,
 encoding just defines a way how data is encoded, which brings us to the first issue.
Download size increase
Although Base64 is a relatively efficient way of encoding binary data it will, on average still increase the file 
size by around 33%. This not only increases your bandwidth bill, but also increases the download time.
Original File size 7.49 kb
       Base64 size 10 kb
CPU Cycles
When delivering images in Base64, the browser first needs to decode the Base64 encoded strings and then decode 
the images as well, which introduces an extra layer of unnecessary work. Base64 is very efficient, but count in in
 the processing time that happens on the server to compress the response and the milliseconds quickly start adding 
up.
Caching Problem
The third issue is perhaps the biggest performance killer, but perhaps not the most obvious at first glance. When
 a user accesses your website, the browser will automatically cache the images locally and then load them directly 
from your disk when visiting the same page again. Due to how Base64 works, the browser is unable to store the
 images locally so it will always need to fetch them from your server or CDN which creates extra load on your 
server as well as increases your bandwidth bill.
Another issue here is that if your images are embedded in your HTML code, content delivery networks such as 
BunnyCDN are not able to cache the files and they will always be returned from your origin server which might 
be thousands of kilometers away.
SEO and User Experience
The issues are actually not only limited to performance. By using Base64 encoded images on your website, you 
might also be hurting both your SEO and user experience as well.
The reason for this is that sharing Base64 images is much harder due to the fact that they are not actually accessible
 via a public URL. This means that web crawlers and your users are unable to get links pointing back to your
 website, which makes sharing content much harder and can potentially hurt your "page rank" as well.
When to actually use Base64?
Base64 has a lot of uses in technology, but unless you have a very good reason, you should try to avoid using it as 
part of your HTML or CSS files. There are some edge cases where Base64 might actually be useful.
One such example would be very small images, where the Base64 string is actually smaller than the length of an 
URL string and HTTP request overhead when linking to an image file. Take for example a 1x1 pixel transparent PNG.
Despite the original image being only 68 bytes in size, factoring in the HTTP headers etc, it actually ends up being 
bigger than the Base64 encoded string:
Empty transparent pixel:

iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=

Google renders the image searches on the search page as base64 for small image icons. 
When the same image is opened in a new tab it is rendered from url. 
If you ever run into a blog that suggests using Base64 to improve performance, make sure to take it with a grain of 
salt and evaluate carefully if there are any real benefits that apply to your own use-case.

Thursday, June 7, 2018

Java Code Coverage IntelliJ and Eclipse


Java Code Coverage using IDE

This article is an effort to improve the JUnit Test code coverage. Following snapshots covers the steps to integrate code coverage tools with IDE on local machine.
IntelliJ
  1. Make sure coverage plugin is installed in IntelliJ
  2. And the Coverage view is enabled

  3. Configure the Junit in run configuration


  4. Following is an example for hraction module
    1. Configuration tab

    2. Code coverage tab, You may select the coverage runner from dropdown. Options are Jacoco and IntelliJ IDEA

  5. Click on run with coverage

  6. To see the coverage results select the class file on which code coverage is to be run and execute the below command:




Eclipse
  1. Install Jacoco Code coverage plugin

  2. Open the Coverage configuration

  3. Configure the details as per your need

  4. Select the project and run coverage from tool window

  5. You get the coverage data in below format




Tuesday, September 29, 2015

JMS Listener

In this article i would like to focus on the message driven bean for activemq.

Prerequisite:

  1. ActiveMq server should be running.
  2. Configure you your topic/queue in the console there 

    3. Configure your application server with activeMQ  resource adapter. e.g. Wildfly module  should         be extracted in wildfly modules directory and same should be configured inside stadalone-                   full.xml.

<subsystem xmlns="urn:jboss:domain:resource-adapters:2.0">
            <resource-adapters>
                <resource-adapter id="activemq-rar.rar">
                    <module slot="main" id="org.apache.activemq"/>
                    <transaction-support>XATransaction</transaction-support>
                    <config-property name="ServerUrl">
                        tcp://localhost:61616
                    </config-property>
                    <config-property name="UserName">
                        defaultUser
                    </config-property>
                    <config-property name="UseInboundSession">
                        false
                    </config-property>
                    <config-property name="Password">
                        defaultPassword
                    </config-property>
                    <connection-definitions>
                        <connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/ConnectionFactory" enabled="true" pool-name="ConnectionFactory">
                            <xa-pool>
                                <min-pool-size>1</min-pool-size>
                                <max-pool-size>20</max-pool-size>
                                <prefill>false</prefill>
                                <is-same-rm-override>false</is-same-rm-override>
                            </xa-pool>
                        </connection-definition>
                    </connection-definitions>
                    <admin-objects>
                        <admin-object class-name="org.apache.activemq.command.ActiveMQTopic" jndi-name="java:jboss/activemq/topic/yourtopic" use-java-context="true" pool-name="hsn18cmstopic">
                            <config-property name="PhysicalName">
                                activemq/topic/yourtopic
                            </config-property>
                        </admin-object>
                    </admin-objects>
                </resource-adapter>
            </resource-adapters>
        </subsystem>



To write your implementation of JMS listener your class should implement the interface MessageListener(javax.jms.MessageListener).

public class YourListener implements MessageListener {


}


You need to specify the activation config parameter inside 'MessageDriven' annotation as follows.

@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "suborderupdates"),
@ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "false") })

Override the onMessage method and try to extract the TextMessage from the message by parsing JSON string.


       @Override
public void onMessage(Message message) {

try {
logger.info("event received");
TextMessage textMsg = (TextMessage) message;
textMsg.getJMSType();
Gson gson = new Gson();
JsonParser parser = new JsonParser();
JsonElement jelement = parser.parse(textMsg.getText())
.getAsJsonObject();
<T> omsEvent = gson.fromJson(jelement,
<T>.class);
//TODO write your code here
} catch (Exception exception) {
exception.printStackTrace();
}
.
Hence the complete class should be something like

/**
 * 
 */


import java.util.logging.Logger;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.inject.Inject;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

/**
 * @author Girish.Yadav
 *
 */
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "suborderupdates"),
@ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "false") })

public class OMSListener implements MessageListener {

private static Logger logger = Logger
.getLogger(OMSListener.class.getName());

@Override
public void onMessage(Message message) {

try {
logger.info("OMS event received");
TextMessage textMsg = (TextMessage) message;
textMsg.getJMSType();
Gson gson = new Gson();
JsonParser parser = new JsonParser();
JsonElement jelement = parser.parse(textMsg.getText())
.getAsJsonObject();
<T> omsEvent = gson.fromJson(jelement,
<T>.class);
//TODO write your code here

} catch (Exception exception) {
exception.printStackTrace();
}

}
}

Wednesday, June 11, 2014

Spiral Traversal of 2 dimensional Array

I would like to share this interesting question which is asked in data structures and algorithms round in some companies:

Problem: How would you traverse a two dimensional array in spiral fashion.


package com.girish.algorithms;

public class SpiralTraversal {


static int ROW_SIZE = 5;
static int COLUMN_SIZE = 6;
static int COLUMNS_TILL_RIGHT=5;
static int ROWS_TILL_DOWN=4;
static int COLUMNS_TILL_LEFT=0;
static int ROWS_TILL_UP=0;
static int[][] Array = new int[][]
{ {1, 2, 3, 4, 5, 6},
{7, 8, 9, 10, 11, 12},
{13, 14, 15, 16, 17, 18},
{19, 20, 21, 22, 23, 24},
{25, 26, 27, 28, 29, 30} };

public static void traverse(int m, int n, boolean directionUp)
{

System.out.println("{"+m+", "+n+"} "+ Array[m][ n]);
// Recurse right
if ((n+1<=COLUMNS_TILL_RIGHT) && !directionUp)
{
traverse(m, n+1, false);
return;
}
// Recurse down

if ((m+1<=ROWS_TILL_DOWN) && !directionUp)
{
traverse(m+1, n, false);
return;
}
// Recurse Left
if ((m > 0 && n >0) && (n-1>COLUMNS_TILL_LEFT))
{
traverse(m, n-1, true);
return;
}
//Recurse up
if ((m > 0) && (m-1>ROWS_TILL_UP))
{
traverse(m-1, n, true);
return;
}
COLUMNS_TILL_RIGHT--;
ROWS_TILL_DOWN--;
COLUMNS_TILL_LEFT++;
ROWS_TILL_UP++;
if ((COLUMNS_TILL_LEFT < COLUMNS_TILL_RIGHT) || (ROWS_TILL_DOWN > ROWS_TILL_UP))
{
traverse (m, n+1, false);
}
}

public static void main(String[] args) {
traverse(0, 0, false);

}

}

Sunday, April 13, 2014

HotSpot JVM GC and performance tuning


Performance tuning is a very interesting topic which offers many things to learn about the JVM and your application.
Every Java application has its own behaviour and its own requirements thus providing a great scope to learn something new while doing tuning.
Mostly developers are focused on working only on the package they are supposed to code. While coding there are lots of faux pas they commit without realizing how it could bring down the performance in the production. I would like to put some thought on how to analyse the JVM tuning and coding practices which are effective to minimize performance glitches.


Heap is divided into 2 parts:



1. Young Generation

Young generation memory consists of two parts, Eden space and 2 survivor spaces. Most objects are initially allocated in eden. One of the survivor spaces is always empty and serves as the destination of any live objects in eden and the other survivor space during the next copying collection. Objects are copied between survivor spaces in this way until they are old enough to be tenured (copied to the tenured generation). Thus Shortlived objects will be available in Eden space. Every object starts its life from Eden space. When GC happens, if an object is still alive and it will be moved to survivor space and other dereferenced objects will be removed.

2. Old Generation – Tenured and Perm Gen

Old generation memory has two parts, tenured generation and permanent generation (Perm Gen). Perm Gen is a popular term. We used to error like Perm Gen space not sufficient.

GC moves live objects from survivor space to tenured generation. The permanent generation contains meta data of the virtual machine, class and method objects.


Performance criteria:

There are two primary measures of garbage collection performance:
  1. Throughput is the percentage of total time not spent in garbage collection, considered over long periods of time. Throughput includes time spent in allocation (but tuning for speed of allocation is generally not needed).
  2. Pauses are the times when an application appears unresponsive because garbage collection is occurring.
  3. Footprint is the working set of a process, measured in pages and cache lines. On systems with limited physical memory or many processes, footprint may dictate scalability. 


In simple terms the goal of tuning is to provide good performance with little or no tuning of command line options by selecting the garbage collector,heap size,and runtime compiler at JVM startup, instead of using fixed defaults.

Selecting a collector:

If the application has a small data set (up to approximately 100MB), then select the serial collector with -XX:+UseSerialGC.
If the application will be run on a single processor and there are no pause time requirements, then let the VM select the collector, or select the serial collector with -XX:+UseSerialGC.
If (a) peak application performance is the first priority and (b) there are no pause time requirements or pauses of one second or longer are acceptable, then let the VM select the collector, or select the parallel collector with -XX:+UseParallelGC and (optionally) enable parallel compaction with -XX:+UseParallelOldGC.
If response time is more important than overall throughput and garbage collection pauses must be kept shorter than approximately one second, then select the concurrent collector with -XX:+UseConcMarkSweepGC. If only one or two processors are available, consider using incremental mode, described below.








Reducing Garbage-Collection Pause Time:

There are two general ways to reduce garbage-collection pause time and the impact it has on application performance:

The garbage collection can itself leverage the existence of multiple CPUs and be executed in parallel. Although the application threads remain fully suspended during this time, the garbage collection can be done in a fraction of the time, effectively reducing the suspension time.
The second approach is to leave the application running, and execute garbage collection concurrently with the application execution.
These two logical solutions have led to the development of serial, parallel, and concurrent garbage-collection strategies, which represent the foundation of all existing Java garbage-collection implementations





The serial collector suspends the application and executes the mark-and-sweep algorithm in a single thread. It is the simplest and oldest form of garbage collection in Java and is still the default in the Oracle HotSpot JVM.

The parallel collector uses multiple threads to do its work. It can therefore decrease the GC pause time by leveraging multiple CPUs. It is often the best choice for throughput applications.

The concurrent collector does the majority of its work concurrent with the application execution. It has to suspend the application for only very short amounts of time. This has a big benefit for response-time–sensitive applications, but is not without drawbacks.

(Mostly) Concurrent Marking and Sweeping
Concurrent garbage-collection strategies complicate the relatively simple mark-and-sweep algorithm a bit. The mark phase is usually sub-divided into some variant of the following:

In the initial marking, the GC root objects are marked as alive. During this phase, all threads of the application are suspended.
During concurrent marking, the marked root objects are traversed and all reachable objects are marked. This phase is fully concurrent with application execution, so all application threads are active and can even allocate new objects. For this reason there might be another phase that marks objects that have been allocated during the concurrent marking. This is sometimes referred to as pre-cleaning and is still done concurrent to the application execution.
In the final marking, all threads are suspended and all remaining newly allocated objects are marked as alive. This is indicated in Figure 2.6 by the re-mark label.
The concurrent mark works mostly, but not completely, without pausing the application. The tradeoff is a more complex algorithm and an additional phase that is not necessary in a normal stop-the-world GC: the final marking.

The Oracle JRockit JVM improves this algorithm with the help of a keep area, which, if you’re interested, is described in detail in the JRockit documentation. New objects are kept separately and not considered garbage during the first GC. This eliminates the need for a final marking or re-mark.

In the sweep phase of the CMS, all memory areas not occupied by marked objects are found and added to the free list. In other words, the objects are swept by the GC. This phase can run at least partially concurrent to the application. For instance, JRockit divides the heap into two areas of equal size and sweeps one then the other. During this phase, no threads are stopped, but allocations take place only in the area that is not actively being swept.

The downsides of the CMS algorithm can be quickly identified:

As the marking phase is concurrent to the application’s execution, the space allocated for objects can surpass the capacity of the CMS, leading to an allocation error.
The free lists immediately lead to memory fragmentation and all this entails.
The algorithm is more complicated than the other two and consequently requires more CPU cycles.
The algorithm requires more fine-tuning and has more configuration options than the other approaches.
These disadvantages aside, the CMS will nearly always lead to greater predictability and better application response time.

Reducing the Impact of Compacting
Modern garbage collectors execute their compacting processes in parallel, leveraging multiple CPUs. Nevertheless, nearly all of them have to suspend the application during this process. JVMs with several gigabytes of memory can be suspended for several seconds or more. To work around this, the various JVMs each implements a set of parameters that can be used to compact memory in smaller, incremental steps instead of as a single big block. The parameters are as follows:

Compacting is executed not for every GC cycle, but only once a certain level of fragmentation is reached (e.g., if more than 50% of the free memory is not continuous).
One can configure a target fragmentation. Instead of compacting everything, the garbage collector compacts only until a designated percentage of the free memory is available as a continuous block.
This works, but the optimization process is tedious, involves a lot of testing, and needs to be done again and again for every application to achieve optimum results.

Sizing of Heap and Various Ratios:



A number of parameters affect generation size. The following diagram illustrates the difference between committed space and virtual space in the heap. At initialization of the virtual machine, the entire space for the heap is reserved. The size of the space reserved can be specified with the -Xmx option. If the value of the -Xms parameter is smaller than the value of the -Xmx parameter, not all of the space that is reserved is immediately committed to the virtual machine. The uncommitted space is labeled "virtual" in this figure. The different parts of the heap (permanent generation, tenured generation and young generation) can grow to the limit of the virtual space as needed.

Some of the parameters are ratios of one part of the heap to another.


Total Heap


Since collections occur when generations fill up, throughput is inversely proportional to the amount of memory available. Total available memory is the most important factor affecting garbage collection performance.

By default, the virtual machine grows or shrinks the heap at each collection to try to keep the proportion of free space to live objects at each collection within a specific range. This target range is set as a percentage by the parameters -XX:MinHeapFreeRatio=<minimum> and -XX:MaxHeapFreeRatio=<maximum>, and the total size is bounded below by -Xms<min> and above by -Xmx<max>. The default parameters for the 32-bit Solaris Operating System (SPARC Platform Edition) are shown in this table:

Parameter
Default Value
MinHeapFreeRatio       40
MaxHeapFreeRatio      70
-Xms    3670k
-Xmx   64m

Lets understand these parameters:

If MinHeapFreeRatio is 40(%) ,  if the percent of free space in a generation falls below 40%, the generation will be expanded to maintain 40% free space, up to the maximum allowed size of the generation. Similarly, if the free space exceeds 70%, the generation will be contracted so that only 70% of the space is free, subject to the minimum size of the generation.

Generally initial heap size for application is very small, thumb rule is unless you have problems with pauses, try granting as much memory as possible to the virtual machine. The default size (64MB) is often too small.

Setting -Xms and -Xmx to the same value increases predictability by removing the most important sizing decision from the virtual machine. However, the virtual machine is then unable to compensate if you make a poor choice.
In general, increase the memory as you increase the number of processors, since allocation can be parallelized.


The Young Generation


The second most influential knob is the proportion of the heap dedicated to the young generation. Larger young generation means lesser minor collections.However, for a fixed heap size if young generation is large that means space for tenured gets reduced and hence major GC occurs frequently.

By default, the young generation size is controlled by NewRatio. For example, setting -XX:NewRatio=3 means that the ratio between the young and tenured generation is 1:3. In other words, the combined size of the eden and survivor spaces will be one fourth of the total heap size.

The parameters NewSize and MaxNewSize bound the young generation size from below and above. Setting these to the same value fixes the young generation, just as setting -Xms and -Xmx to the same value fixes the total heap size. This is useful for tuning the young generation at a finer granularity than the integral multiples allowed by NewRatio.

Survivor Space Sizing

Though we can confiure the survivor space sizing but from performance perspective it is not that important.For example, -XX:SurvivorRatio=n sets the ratio between eden and a survivor space to 1:n. In other words, each survivor space will be one nth the size of eden, and thus one (n+2)th the size of the young generation (not one (n+1)th, because there are two survivor spaces).

If survivor spaces are too small, copying collection overflows directly into the tenured generation. If survivor spaces are too large, they will be uselessly empty.

Here are the default values for the 32-bit Solaris Operating System (SPARC Platform Edition); the default values on other platforms are different.

            Default Value
Parameter
Client JVM
Server JVM
NewRatio         8          2
NewSize          2228K 2228K
MaxNewSize   not limited         not limited
SurvivorRatio   32        32
The maximum size of the young generation will be calculated from the maximum size of the total heap and NewRatio. The "not limited" default value for MaxNewSize means that the calculated value is not limited by MaxNewSize unless a value for MaxNewSize is specified on the command line.



The steps for server applications for setting parameters are:

First decide the maximum heap size you can afford to give the virtual machine. Then tune the young generation size to give you optimum/best results.
Note that the maximum heap size should always be smaller than the amount of memory installed on the machine, to avoid excessive page faults and thrashing.
If the total heap size is fixed, increasing the young generation size requires reducing the tenured generation size. Keep the tenured generation large enough to hold all the live data used by the application at any given time, plus some amount of slack space (10-20% or more).

Subject to the above constraint on the tenured generation:
Grant plenty of memory to the young generation.
Increase the young generation size as you increase the number of processors, since allocation can be parallelized.


Optimization:


Optimization is an art. There are no magical data structures capable of solving every problem. As you can see, you have to fight for every byte. Memory optimization is a complex process. Remember that you should design your data so each object can be referenced from different collections (instead of having to copy data). It is usually better to use semantically immutable objects because you can easily share them instead of copying them. And from my experience, in a well-designed application, optimization and tuning can reduce memory usage by 30-50%.