Showing posts with label performance. Show all posts
Showing posts with label performance. Show all posts

Saturday, July 22, 2017

Java: Splitting a Pipe-delimited String - Fast!

This post shows how you can efficiently split a pipe-delimited string e.g. "foo|bar|baz". There are many ways to do this - I could even write my own - but I will only use those that are available in the JDK (or commonly used libraries) and will measure the performance of each.

Remember that, since the pipe symbol (|) is a special character in regular expressions, it needs to be escaped if necessary.

1. String.split

The most obvious way to split a string on the pipe character is to use Java's String.split:

public static String[] split(String s) {
  return s.split("\\|");
}

2. String.split with Pattern.quote

Instead of escaping the pipe ourselves, we can use Pattern.quote to do it for us. (Note: Pattern.quote("|") returns "\Q|\E".)

public static String[] splitWithPatternQuote(String s) {
  return s.split(Pattern.quote("|"));
}

3. Pattern.split

Create a static Pattern and use it to split the string.

private static final Pattern SPLITTER = Pattern.compile("\\|");

public static String[] splitWithPattern(String s) {
  return SPLITTER.split(s);
}

4. StringUtils.split

Apache Commons provides StringUtils.split, which splits a string on a single character:

import org.apache.commons.lang3.StringUtils;

public static String[] splitWithStringUtils(String s) {
  return StringUtils.split(s, '|');
}

So, which one is fastest?

I ran each method on 1 million pipe-delimited strings of different lengths - RandomStringUtils.randomAlphabetic is great for generating random strings - and the table below shows how long each one took:

MethodTime (ms)
split485
splitWithStringUtils520
splitWithPattern643
splitWithPatternQuote936

An interesting observation is that splitWithPatternQuote is so much slower than split, even though they both call String.split internally! If we delve into the source code for String.split, we can see that there is an optimisation (a "fastpath") if the provided regex has two-chars and the first char is a backslash. This applies to "\\|" but, since Pattern.quote produces \Q|\E, it does not use the fastpath and instead creates a new Pattern object for every split. This also explains why it is slower than splitWithPattern, which re-uses the same Pattern object.

Saturday, November 22, 2014

Ext JS - Caching AJAX Responses to HTML5 Web Storage for Better Performance

This post shows how you can improve performance of your Ext JS applications by using a "Caching AJAX Proxy". This proxy saves URL responses to HTML5 Web Storage (e.g. session storage or local storage), which means that when the same URL is requested multiple times, a cached response is returned, instead of sending a request to the server each time. This makes the application more responsive and also reduces load on the server handling the requests.

/**
 * A Caching Ajax Proxy which uses AJAX requests to get data from a server and
 * then stores the data to HTML5 Web Storage. If the storage fills up, it removes
 * entries from the cache until space is available.
 * (Compatible with Ext JS 4.2)
 */
Ext.define('App.data.proxy.CachingAjax', {
  extend: 'Ext.data.proxy.Ajax',
  alias: 'proxy.cachingajax',

  // use session storage, but can be configured to localStorage too
  storage: window.sessionStorage,

  // @Override
  doRequest: function(operation, callback, scope) {
    var cachedResponse = this.getItemFromCache(this.url);
    if (!cachedResponse) {
        this.callParent(arguments);
    }
    else {
        console.log('Got cached data for: ' + this.url);
        this.processResponse(true, operation, null, cachedResponse,
                             callback, scope, true);
    }
  },

  // @Override
  processResponse: function(success, operation, request, response,
                            callback, scope, isCached) {
    if (success === true && !isCached) {
        this.putItemInCache(this.url, response.responseText);
    }
    this.callParent(arguments);
  },

  /**
   * @private
   * Returns the data from the cache for the specified key
   * @param {String} the url
   * @return {String} the cached url response, or null if not in cache
   */
  getItemFromCache: function(key) {
    return this.storage ? this.storage.getItem(key) : null;
  },

  /**
   * @private
   * Puts an entry in the cache.
   * Removes a third of the entries if the cache is full.
   * @param {String} the url
   * @param {String} the data
   */
  putItemInCache: function(key, value) {
    if (!this.storage) return;
    try {
      this.storage.setItem(key, value);
    } catch (e) {
      // this might happen if the storage is full.
      // Remove a third of the items and retry.
      // If it fails again, disable the cache quietly.
      console.log('Error putting data in cache. CacheSize: ' + this.storage.length +
                  ', ErrorCode: ' + e.code + ', Message: ' + e.name);

      while (this.storage.length != 0) {
        var toRemove = this.storage.length / 3;
        for (var i = 0; i < toRemove ; i++) {
          var item = this.storage.key(0);
          if (item) this.storage.removeItem(item);
          else break;
        }
        console.log('Removed one-third of the cache. Cache size is now: ' + this.storage.length);
        try {
          this.storage.setItem(key, value);
          break;
        } catch (e) {
          console.log('Error putting data in cache again. CacheSize: ' + this.storage.length +
                      ', ErrorCode: ' + e.code + ', Message: ' + e.name);
        }
      }
      if (this.storage.length == 0) {
        console.log("Cache disabled");
        this.storage = null;
      }
    }
  }
});
Usage:
var store = Ext.create('Ext.data.Store', {
  model: 'User',
  proxy: {
    type: 'cachingajax',
    url : 'http://mywebsite/path'
  }
});

Obviously, you should only use this caching proxy when the server-side data is static, because if it is changing frequently your application will end up displaying stale, cached data.

This proxy can also be extended in the future to remove cached entries after specific time intervals or clear out the entire cache when the application starts up.

Saturday, January 07, 2012

Stackless Exceptions for Improved Performance

One of the reasons for standard exceptions being slow is that they have to fill in the execution stack trace for the current thread. Although, this is useful for debugging, in most cases you don't really care about the stack trace. What you care about is that an exception of a certain type was thrown and what the error message was. For example, a java.io.FileNotFoundException was thrown with message config.xml (The system cannot find the file specified)".

Stackless Exceptions are exceptions without any associated stack information. They are faster to create than normal exceptions because they don't record information about the current state of the stack frames for the current thread.

The class below is an example of a stackless exception. The fillInStackTrace method has been overridden so that it doesn't do anything and simply returns the current instance.

/**
 * An exception which does not fill in a stack trace
 * for performance reasons.
 */
@SuppressWarnings("serial")
public class StacklessException extends Exception {

    /**
     * Constructs a new stackless exception
     * with the specified detail message.
     *
     * @param message the detail message.
     * @see java.lang.Exception#Exception(String)
     */
    public StacklessException(String message) {
        super(message);
    }

    /**
     * Does not fill in the stack trace for this exception
     * for performance reasons.
     *
     * @return this instance
     * @see java.lang.Throwable#fillInStackTrace()
     */
    @Override
    public Throwable fillInStackTrace() {
        return this;
    }
}
I measured performance by comparing the time taken to create a million StacklessException and Exception objects. I found that the creation of stackless exceptions is nearly 40 times faster than normal exceptions.

You can then create more specific exception types which subclass StacklessException. For example:

public class PersonNotFoundException extends StacklessException {
    public PersonNotFoundException(String message) {
        super(message);
    }
}
As an aside, note that the JVM omits stack traces if an exception is thrown very frequently. This optimisation is enabled by default and can be disabled using the JVM option -XX:-OmitStackTraceInFastThrow.

Saturday, August 29, 2009

Speed up Eclipse

I've just noticed a big performance improvement in Eclipse 3.5 (Galileo), just by launching it with the latest JRE (1.6.0_16) and unlocking the new G1 garbage collector. My startup time has reduced from about 30 secs to 4-5 secs and the interface is snappier.

Here is my eclipse.ini:

-startup
plugins/org.eclipse.equinox.launcher_1.0.200.v20090520.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.0.200.v20090519
-product
org.eclipse.epp.package.java.product
-data
c:\eclipse
-showlocation
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
384m
-vm
C:\program files\Java\jdk1.6.0_16\jre\bin\client\jvm.dll
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Xms128m
-Xmx384m
-Xss4m
-XX:PermSize=128m
-XX:MaxPermSize=128m
-XX:CompileThreshold=5
-XX:MaxGCPauseMillis=10
-XX:MaxHeapFreeRatio=70
-XX:+UnlockExperimentalVMOptions
-XX:+UseG1GC
-XX:+UseFastAccessorMethods
-XX:+AggressiveOpts
-Dcom.sun.management.jmxremote
Let me know if there are any other improvements I can make!

Monday, March 26, 2007

Windows XP Performance Tips

WINDOWS DISK INDEXING
This is a performance tip that I strongly recommend you implement. The Windows Disk Indexer constantly indexes all files on your machine to allow for faster searching using the Windows Search function for example. Since most people don't search their machine very often, having Disk Indexing enabled provides a performance hit for no good reason, and also increases fragmentation. Follow these steps to turn off the Windows Disk Indexer to improve hard drive performance and responsiveness:
1. Go to Windows Explorer, right-click on your hard drive name (e.g. C:) and select Properties.
2. Untick the 'Allow Indexing Service to index this disk for fast file searching'.
3. Select 'Apply changes to [Drive letter]\, subfolders and files' in the subsequent prompt.
4. Your system will now go through and remove all indexing on existing files, and not index any new or moved files in the future - this will speed up drive read/writes and general responsiveness. Ignore any 'errors' which are shown, this occurs simply because some files are in use or protected and can't have their properties changed to remove indexing - this is normal.

Make sure you also disable the 'Indexing Service' service as it is no longer necessary when disk indexing is removed from your hard drive.

DEFRAGMENTATION
I strongly suggest you get into the habit of defragmenting often, specifically after you delete or add large files or install software.

PREFETCH
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory
Management\PrefetchParameters]
EnablePrefetcher=3

I personally leave the Prefetcher registry setting above at its default of 3, and set the Task Scheduler service to Disabled. This means the prefetcher won't create application prefetch files under the Window\Prefetch directory. I also clear all out existing prefetch (.PF) files in that directory. I have found that this provides for the fastest Windows bootup time.

CONTROL PANEL > SYSTEM

> ADVANCED > PERFORMANCE SETTINGS
For fastest performance, I recommend deselecting everything except 'Use visual styles on windows and buttons' and 'Use drop shadows for icon labels on the desktop'. That will reduce usage of system resources for graphical effects, while still retaining the majority of Windows XP's trademark appearance.

> ADVANCED > PERFORMANCE SETTINGS > ADVANCED > VIRTUAL MEMORY


This is where you can set the size of your pagefile. To determine the optimal pagefile size you should ideally see how much memory your most memory intensive programs use and then set the pagefile to comfortably accommodate this.

Before setting a new pagefile size, first clear your existing pagefile. To do this select the 'No Paging File' option and click the Set button, then reboot your system. This step does two things: first it deletes the pagefile, fixing any potential pagefile corruption which can occur after a bad shutdown (remember this tip for future troubleshooting purposes); and secondly it ensures that any new pagefile you create will start off as a single unfragmented contiguous block on your hard drive for optimal performance, which will remain unfragmented in the future. Note that if you have any problems booting up into Windows due to a lack of a pagefile during this step, enter Windows in Safe Mode (See Backup & Recovery section) and continue the setup procedures for Virtual Memory from there.

Here is a simple general recommendation which is both safe to use on all systems, regardless of how much RAM you have, and provides good performance:
Set the Initial and Maximum pagefile sizes to 2560MB each - i.e. allocate 2.5GB for the pagefile. Whatever you do, don't set a zero pagefile.

> ADVANCED > STARTUP & RECOVERY SETTINGS
For a system with a single operating system, select '"Microsoft Windows XP [Home/Professional]" /fastdetect' in the list presented. If you only have one operating system, or you don't want to select a different operating system each time you boot up, untick the 'Time to display list of Operating Systems' option.

Under the 'System failure' section untick all three options for optimal performance, and the 'Write Debugging Information' option should be set to None. That way if you run into problems you'll see the error displayed (usually a Windows Blue Screen of Death (BSOD) message) and your system won't automatically reboot. At the same time you won't get lots of logfiles and dumpfiles of the event cluttering up your hard drive.

> ADVANCED > ERROR REPORTING
Click the Error Reporting button and select 'Disable Error Reporting' and tick 'But notify me when critical errors occur'. This will prevent your system continually informing Microsoft of errors occurring on your system, but at the same time will still show you important system messages and errors for notification and troubleshooting purposes.

> REMOTE
I strongly recommend that you disable the available options in this section for security and performance reasons.

> AUTOMATIC UPDATES
I recommend 'Turn off Automatic Updates' and instead use the manual method of regularly checking the Windows Update site for updates.

> SYSTEM RESTORE
Turn off System Restore, as it can take up a great deal of disk space

CONTROL PANEL > SOUNDS & AUDIO DEVICES
Disable as many sounds as possible as they take up system memory by being loaded into RAM at startup.

CONTROL PANEL > FOLDER OPTIONS
Use Windows Classic Folders
Open each folder in the same window
Double-click to open an item
Under View, I recommend you tick the following options:
  • Display file size information in folder tips
  • Display simple folder view in Explorer's folder list
  • Display the contents of system folders
  • Display the full path in the address bar
  • Display the full path in the title bar
  • Do not cache thumbnails
  • Show hidden files and folders
  • Show Control Panel in My Computer
  • Show encrypted or compressed NTFS files in color
It is recommended that the rest are unticked for best performance and functionality.

MOUSE
  • untick pointer shadow
  • auto default dialog button jump
  • pointer precision

SCREENSAVER
I recommend you set the screen saver to None to prevent burn-in (permanent image imprinting)

DISABLE STARTUP PROCESSES
Go to Run > msconfig and then choose the Startup tab.
Examine the list and disable any items you do not want started when your computer boots e.g. ypager, iTunesHelper etc.

DISABLE SERVICES
Go to Run > services.msc and then disable the following:
  • .NET Runtime Optimization Service
  • ASP.NET State Service
  • Clipbook
  • Error Reporting Service
  • Fast User Switching Compatibility
  • IMAPI CD-Burning COM Service
  • Indexing Service
  • Infrared Monitor
  • Machine Debug Manager
  • NetMeeting Remote Desktop Sharing
  • Network DDE
  • Network DDE DSM
  • Network Location Awareness (NLA)
  • Performance Logs and Alerts
  • Portable Media Serial Number Service
  • QoS RSVP
  • Remote Desktop Help Session Manager
  • Remote Registry
  • Routing and Remote Access
  • Secondary Logon
  • Security Center
  • Smart Card
  • SSDP Discovery Service
  • TCP/IP NetBIOS Helper
  • Telnet
  • Terminal Services
  • Uninterruptible Power Supply
  • Volume Shadow Copy
  • WebClient
  • Windows CardSpace
  • Windows User Mode Driver Framework
  • Wireless Zero Configuration
  • WMI Performance Adapter