Analyzing Transaction Lock Contention

The transaction statistic can show which classes are involved in transaction lock contention. Often, this is sufficient to help the developer already familiar with the application, identify application changes for reducing the contention. For cases where the code paths involved in the contention are not already known, the transactioncontention statistic can be useful.

Enabling the transactioncontention statistic causes the TIBCO StreamBase® Runtime runtime to collect a stack backtrace each time a transaction lock encounters contention. The stacks are saved per managed class name.

[Note]

The collection of transaction contention statistics is very expensive computationally and should only be used in development or test systems.

To use transaction contention statistics, enable them with the epadmin enable statistics --statistics=transactioncontention command.

If your application is not already running, start it. This example uses the TransactionContention snippet shown below.

package com.tibco.ep.dtm.snippets.tuning;

import com.kabira.platform.Transaction;
import com.kabira.platform.annotation.Managed;

/**
 * Simple transaction contention generator
 * <p>
 * Note this sample needs to be explicitly stopped.
 */
public class TransactionContention
{
	
    /**
     * Main entry point
     * @param args Not used
     */
    public static void main(String[] args)
    {
        //
        // Create a managed object to use for
        // generating transaction lock contention
        //
        final MyManaged myManaged = createMyManaged();

        //
        // Create/start a thread which will
        // transactionally contend for the object.
        // 
        new MyThread(myManaged).start();

        while (true)
        {
            //
            // Contend for the object here
            // from // the main thread (competing
            // with the thread started above).
            //
            generateContention(myManaged);
            nap(200);
        }
    }

    private static MyManaged createMyManaged()
    {
        return new Transaction("createMyManaged")
        {
            MyManaged m_object;

            @Override
            protected void run()
            {
                m_object = new MyManaged();
            }

            MyManaged create()
            {
                execute();
                return m_object;
            }
        }.create();
    }

    private static void generateContention(final MyManaged myManaged)
    {
        new Transaction("generateContention")
        {
            @Override
            protected void run()
            {
                writeLockObject(myManaged);
            }
        }.execute();
    }

    @Managed
    private static class MyManaged
    {
    }

    private static void nap(int milliseconds)
    {
        try
        {
            Thread.sleep(milliseconds);
        }
        catch (InterruptedException e)
        {
        }
    }

    private static class MyThread extends Thread
    {
        MyManaged m_object;

        MyThread(MyManaged myManaged)
        {
            m_object = myManaged;
        }

        @Override
        public void run()
        {
            while (true)
            {
                generateContention(m_object);
                nap(200);
            }
        }
    }
}

After your application has run long enough to generate some transaction lock contention, stop the data collection with the epadmin disable statistics statistics=transactioncontention command.

Display the collected data with the epadmin display statistics --statistics=transactioncontention command.

======== transaction contention report for A ========

24 occurrences on type com.kabira.snippets.tuning.TransactionContention$MyManaged of stack:

	com.kabira.platform.Transaction.lockObject(Native Method)
	com.kabira.platform.Transaction.writeLockObject(Transaction.java:706)
	com.kabira.snippets.tuning.TransactionContention$2.run(TransactionContention.java:48)
	com.kabira.platform.Transaction.execute(Transaction.java:484)
	com.kabira.platform.Transaction.execute(Transaction.java:542)
	com.kabira.snippets.tuning.TransactionContention.generateContention(TransactionContention.java:43)
	com.kabira.snippets.tuning.TransactionContention$MyThread.run(TransactionContention.java:84)

57 occurrences on type com.kabira.snippets.tuning.TransactionContention$MyManaged of stack:

	com.kabira.platform.Transaction.lockObject(Native Method)
	com.kabira.platform.Transaction.writeLockObject(Transaction.java:706)
	com.kabira.snippets.tuning.TransactionContention$2.run(TransactionContention.java:48)
	com.kabira.platform.Transaction.execute(Transaction.java:484)
	com.kabira.platform.Transaction.execute(Transaction.java:542)
	com.kabira.snippets.tuning.TransactionContention.generateContention(TransactionContention.java:43)
	com.kabira.snippets.tuning.TransactionContention.main(TransactionContention.java:16)
	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	java.lang.reflect.Method.invoke(Method.java:483)
	com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	java.lang.reflect.Method.invoke(Method.java:483)
	com.kabira.platform.MainWrapper.invokeMain(MainWrapper.java:65)
    

This output shows the two call paths which experienced contention.

The collected data may be cleared with the epadmin clear statistics --statistics=transactioncontention command.