Request your free trial!


Fill out the two fields below and we will contact you to schedule your free trial.

Thank you! We will contact you to schedule your trial.

Geplaatst: 1 October 2018

Oracle ADF Performance: Top 10 Typical Bottlenecks

In this blog I will discuss the top 10 typical performance problems I see in general in Oracle ADF projects – and will discuss solutions.

Top 10 Typical Bottlenecks – Illustrated by ADF Callstacks

I will illustrate the top 10 typical bottlenecks with ‘ADF callstacks’ – a feature of the ADF Performance Monitor. An ADF callstack, a kind of snapshot of the ADF framework, gives visibility into which ADF methods caused other methods/operations to be executed, organized by the sequence of their execution. A complete breakdown of the HTTP request is shown by actions in the ADF framework (Fusion lifecycle phases, model (BindingContainer) and ADF BC executions, start & end of taskflows, e.g.), with elapsed times in milliseconds and a view of what happened when. The parts of the ADF Request that consume a lot of time are highlighted and indicated with an alert signal.

Nr 1: Slow ViewObject SQL Queries

The number one bottleneck is – as is in many web applications – SQL queries of ViewObjects to the database. This can be caused by many things: the SQL query is written in a suboptimal way, the data model is not efficient, the datasets in the database are far too high, indexes are lacking, indexes are not working as expected, e.g.

The first step is to get visibility and see which SQL queries are slow – and with what runtime parameter values:

In this blog is described in detail how you can instrument your ViewObect to get visibility into slow ViewObject queries.

It is always god to be able to analyze the runtime generated SQL (including applied ViewCriteria, and runtime bind parameter values) that is executed in the database. This to be able to reproduce problematic slow queries:

Nr 2: Too Frequent and Slow ApplicationModule Pooling

A very typical and big bottleneck in ADF is too frequent and too slow ApplicationModule Pooling. ApplicationModule pooling is a mechanism in ADF that enables multiple users to share several application module instances. It involves saving and retrieving session state data from the database or file. This mechanism is provided to make the application scalable and becomes very important under high load with many concurrent users. The default values of ApplicationModule pools are far too small; especially if you have more than 10 end-users.

I think this is one of the most important things to tune in general in ADF applications. Activations and passivations are the root cause of many very slow click actions. It is the root cause of errors after incomplete activations. In general, in my experience it is better to try to turn off the whole ApplicationModule pooling mechanism – for so far as it is possible.

Look at an example – a callstack showing what can happen when passivation/activation is not configured well. When there are too many ViewObject rows and attributes in memory, and passivated/activated:

We can see in the callstack:

To avoid the expensive passivations/activations we can increase the size of the ApplicationModule pools. In this way we make the application more scalable and avoid the passivations/activations. I usually increase the following parameters – depending of the usage:

Further:

If you want to know more on ApplicationModule pools and tuning watch the video I made on ADF Performance tuning a few years ago (a big part of the video is on pooling parameters).

Nr 3: Redundant ViewAccessor Processing

The default value of the property of Row Level Bind Values on a ViewObject ViewAccessor is true. Set this value explicitly to false if you have no bind variables that really depend other attribute values in the row. This property is meant to set if there are bind variables in the lookup view object that can have a different value for each row. The first time it really executes the query, the second time the framework still calls the method executeQueryForCollection() on the ViewObject. Internally, in the ADF framework, it recognizes that the query already has been executed, and does not execute the query itself to the database again.

However, it is still a big inefficiency that for all rows the executeQueryForCollection() method is executed, and internally processed in the ADF framework. As we can see in the example below (callstack metrics of the ADF Performance Monitor in JDeveloper console log), this whole process still takes around 200 milliseconds extra for 35 rows (check the execution timeline on the left).

Now we set it to false:

After we set it to false there will be far less processing internally in the ADF framework. The query is executed once, and not any more for each row the whole ViewAccessor is evaluated. The whole HTTP request is around 200 milliseconds faster:

Nr 4: Memory Overconsumption (Fetching Too Many Database Rows and Attributes)

ADF applications potentially use a lot of JVM memory. Many times, the root cause of a high memory usage is that application data retrieved from the database into memory is not properly bounded; too many rows are fetched and held in ADF BC memory. This can lead to memory over-consumption, very long running JVM garbage collections, a freeze of all current requests or even OutOfMemoryErrors. To make matters worse, these rows and their attributes are frequently passivated and activated for an unnecessary long period of time. The solution to this problem can be found in reducing the size of sessions by decreasing of the amount of data loaded and held in the session.

Developing a plan to manage and monitor this fetched data during the whole lifetime of an application is an absolute must. It is indispensable to your performance success. The first step is to measure the current number of rows fetched by the ADF application and determine the appropriate maximum fetch sizes for your data collections. You can measure real-time and historically how many rows the ViewObjects load into Java memory with the ADFBC Memory Analyzer. Limit all Viewobjects, that frequently fetch more than 500 rows on a regular basis, with a maximum fetchsize. Or use extra bind variables, add extra ViewCriteria to limit the number of rows.

Read more in two of my previous blog on managing fetched data from the database, and on limiting the memory consumption of an ADF application:

In the screenshot we can see that nearly two billion rows (!), to be precise 1.855.223, were loaded in the JVM memory of our server. This proces of loading took 186.538 milliseconds (186 seconds).

Nr 5: Slow PL/SQL Executions executed from ADF application

Just like SQL queries from ViewObjects, PLSQL procedures/functions executed from the ADF application be very slow if not implemented well:

In the screenshot we see a PLSQL procedure call hr_main.sleep() with a bind param value of 4. The whole execution takes 4004 milliseconds (more than 4 seconds).

In this case the PLSQL procedure/function is the root cause, not the ADF application code in the ADF application. The problems must be resolved in the database, and can be anything; suboptimal written SQL queries in the procedure/function, the data model is not efficient, the datasets in the procedure/function are far too high, e.g.

Nr 6: ‘Too Rich’ Pages Result in Slow Browser Load Time

We shouldn’t make our ADF pages too ‘rich’ – we should limit the number of ADF Faces components to some extent. Especially the content of ADF Faces container components. Rendering too many table columns – in combination with sending too many rows to the browser – causes a long browser load time. The same applies to af:listView, af:tree and af:treeTable components with hundreds of rows. But also, other container components like af:iterator – when too many child components are rendered – the browser needs seconds to do the hard work.

For example: the loading of a table component (lazy loading of an af:table component showing Locations) takes around 1 to 1.5 seconds (grey color represents browser load time):

A page should spent not more than half a second or less in the browser to load.

Some general tips:

-af:pageTemplate
-af:region
-af:panelCollection
-af:table
-af:treetable
-af:tree
-af:ListView
-af:iterator

Read more on this subject in one of my previous blogs on slow browser load time.

Nr 7: End-Users on Slow Internet Explorer

Many companies and organizations do have the complete control over which type of browser end-users are using. They have control over it because they have a Citrix environment or internal network where end-users work on. Many times, still Internet Explorer is the only browser that is installed and allowed to use.

Web applications in general, and ADF applications in particular, perform very poor in Internet Explorer (regardless of the version). This is because of the inefficient JavaScript engine and the very slow browser load time. Google Chrome and Firefox are currently the most performance friendly browsers. This is very well known under developers. Still many companies, that do have the possibility to change to Chrome/Firefox, insist on Internet Explorer/Edge. My estimation is that changing to Chrome/Firefox will improve the performance in general with 20% or more. In general, it is a good practice to stimulate end-users to install and use Google Chrome or Firefox for ADF applications.

On the next screenshot we can see in which layer processing time has been spent; database (yellow), webservice (pink), application server (blue), network (purple), and browser load time (grey).

In this example from a field report, more than one third of the time spent in is grey, meaning that more than one third of the process time is spent in the browser (!). This is the process time spent by the browser, after receiving the response from the server, to build the DOM-tree  and to render/load the content. It turned out that all end-users were using Internet Explorer 11.

Nr 8: Slow SOAP/REST Webservice Calls

SOAP/REST Webservice calls can be consume a lot of time as well – depending on the network time, and the response time of the webservice request. It is good to have insight into this, especially if the response time takes very long:

In the above screenshot we can see three very slow SOAP webservice calls (executed in 4085, 5347, and 15321 milliseconds(!) ).

Nr 9: Inefficient ViewObject fetchsize

Many developers do not set the fetchSize every time on a ViewObject when they create a ViewObject. The default size of 1 is very inefficient. For example, a page with a table of only the EmployeesViewObject. The fetchsize is 1; this means that for each row the ADF application makes a complete roundtrip to the database (very inefficient):

The time to fetch the 107 employee rows takes 56 milliseconds. Not that super much, but it can be far more efficient, for example with a fetchsize of 120 (using 1 roundtrip to the database):

Now the fetch action takes only 11 milliseconds (we win 45 milliseconds). This seems to be minimal, but if you do this on each ViewObject this will be much better the for the performance!

Nr 10: ChangeEventPolicy is set to PPR

From ADF Release 11G R2 and onwards, the default value is of the global ChangeEventPolicy property is ppr. This is not good for performance, as there is a lot of performance overhead in this property. Too many iterators and components are automatically refreshed on each HTTP request.

In my opinion it is better to change it to none:

You better use manual partialTriggers in the page to refresh components. Be aware that if you change it in your current application, you should add the manual partialTriggers and test if everything works.

Conclusion

Of course, there are many, many more possible causes of poor performance (not well configured JVM, JVM heap too small, long running JVM garbage collections, slow network, hardware, e.g.), but these were our top ten typical bottlenecks we see frequently at companies that use the ADF Performance Monitor.


Tags: , , , , , , , ,

Geplaatst: 7 August 2018

ADF Performance Tuning: A Field Report

Last week I was doing an extensive performance analysis / health check on a large ADF project, with the newest version of our ADF Performance Monitor product. In this performance assessment/analysis I have focused high-level on the most important performance bottlenecks. We could see in the ADF Performance Monitor that end-users experience very slow page load times, they were waiting much more than needed. This ADF application needed attention; it could run more efficient like nearly all ADF applications can. In this blog I describe some of my findings, maybe interesting for other ADF projects as well.

Complete overview

The first thing I always do is configuring the ADF Performance Monitor on all WebLogic managed servers (in this case 4) to have a complete overview of the performance:

In this case a typical daily performance summary was (top left section):

What already is strange here is that the AVG total time end-users needs to wait (0,57 Sec) is more than double the time the AVG process time by the application server (0,25 Sec)!

Problem 1: Very Slow Browser Load Time

On the chart at the right bottom we can see the explanation for this. In this chart we see in a glance in which layer processing time has been spent; database (yellow), webservice (pink), application server (blue), network (purple), and browser load time (grey).

More than one third of the time spent in is grey, meaning that more than one third of the process time is spent in the browser! This is the time spent by the browser, after receiving the response from the server to build the DOM-tree, and rendering/loading the content. Also, as we can see the purple color representing the time spent in the network (HTTP request network time, HTTP response network time) is relatively high: around 1/6th of a request on average. This is far more compared to other ADF projects.

This is the biggest ‘bottleneck’. It turned out that Explorer 11 was the current (and the only installed browser) of all their end-users, installed on its Citrix workstations. Web applications in general, and ADF applications in particular, perform very poor in Internet Explorer (regardless of the version). This is because of the inefficient JavaScript engine and the very slow browser load time. My first recommendation: install and use Google Chrome or Firefox as web browser as these have a very fast browser load time, and very performance friendly browsers. My estimation is that this will improve the performance in general with at least 25% or more for this project. Read here more on browser load time in ADF apps. In generally it is a good practice to stimulate end-users to install and use use Google Chrome or Firefox for ADF applications.

Click Actions Analysis

The next analysis was an ADF click action analysis. A click action is the start trigger event of an HTTP request by the browser, by an action that a user takes within the UI. These are most often physical clicks of end-users on UI elements such as buttons, links, icons, charts, and tabs. But it can also be scrolling and selection events on tables, rendering of charts, polling events, auto-submits of input fields and much more. With monitoring by click action you get insight in the click actions that have the worst performance.

I go very frequently to this overview to see what click action has the worst performance (is responsible for the most total processing time, and thus where we can win the most in terms of performance):

We see here that a poll event (ADF Faces component of type oracle.adf.RichPoll, with id ‘p1′) is responsible by far for the most total processing time (!). On this day there were in total 106.855 poll requests. That is more than one third of all the HTTP requests (296.435)!

Problem 2: Far Too Often Polling

There was a mechanism implemented in the application to force an end-user to be logged in at maximum one time. The way this was implemented was very bad for the server load; every minute a poll (HTTP request) was send to the WebLogic server that called Java code that updated a database table. It had also a side-effect that many end-user sessions were kept alive on the server for many hours (even for the many inactive users that never closed their browser window). The poll was responsible for the most time-consuming action in the application in terms of serving processing time. For now, as we couldn’t change this whole functionality quickly, we reduced the number of calls to three times less (one third now); we kept the same polling mechanism but now every three minutes (to avoid 2/3 of all the polling and to reduce the server load as well). Of course, later we should find an alternative solution.

We saw that the poll caused many very slow HTTP requests that included very slow database queries, frequent expensive ApplicationModule pooling, and other slow executions because it was restoring pages after passivation. It was responsible for 1/3 of all the processing time of the most frequent actions:

Problem 3: Memory Overconsumption

The third – a typical bottleneck in ADF – was an increase in response time (and decline in performance) because of the huge memory usage. The cause of this huge memory usage is that the application data which is retrieved from the database into memory is not properly limited; too many rows (thousands). To make matters worse, these rows and their attributes were retained in the session for an unnecessary period of time (by very frequent expensive ApplicationModule pooling). We can see in the ADFBC Memory Analyzer the total number of rows fetched by ViewObjects at runtime, and the maximum fetched rows. In this case we saw many ViewObjects fetching thousands of rows during an HTTP request:

The solution of this main problem is found in reducing the size of sessions by decreasing of the amount of data loaded and held in the session (setting maximum fetchsizes, adding bind params, fixing ViewCriterias). We have already identified all the locations in the source code and solved the most important of this list. Read more on this subject here.

Problem 4: Too Frequent ‘Expensive’ ApplicationModule Passivations & Activations.

As you know ApplicationModule pooling is a mechanism in ADF that enables multiple users to share several application module instances. It involves saving and retrieving session state data from the database or file. This mechanism is provided to make the application scalable and becomes very important under high load with many concurrent users. The default values of ApplicationModule pools are far too small; especially if you have more than 10 end-users.

I think this is one of the most important things to ‘tune’ in general in ADF applications. Activations and passivations are the root cause of many very slow click actions. It is the root cause of errors after incomplete activations. In general, in my opinion it is better to try to turn off the whole ApplicationModule pooling mechanism – for so far as it is possible.

To do this we increased the size of all the ApplicationModule pools. In this way we make the application more scalable and avoid very expensive passivations and activations. We increased the following parameters – depending of the usage.

Further:

If you want to know more on ApplicationModule pools and tuning watch the video I made on ADF Performance tuning a few years ago (a big part of the video is on pooling parameters).

Problem 5: Too many UIShell Tabs Could be Opened Simultaneously

This was a UIShell application. To avoid resource (but also memory) overconsumption we reduced the maximum number of opened tabs from 10 to 5. This will reduce the resource and memory consumption of the server as well and force the end-user to close unused tabs (and free up resources).

Conclusion

We have found many other bottlenecks as well. But already addressing/resolving these 5 big bottlenecks we have put already a smile on the face of many end-users!


Tags: , , , , , , ,

Geplaatst: 9 July 2018

ADF Performance Monitor: Monitoring with Percentiles

What is best metric in performance monitoring – averages or percentiles? Statistically speaking there are many methods to determine just how good of an overall experience your application is providing. Averages are used widely. They are easy to understand and calculate – however they can be misleading.

This blog is on percentiles. Percentiles are part of our recent new 7.0 version of the ADF Performance Monitor. I will explain what percentiles are and how they can be used to understand your ADF application performance better. Percentiles, when compared with averages, tell us how consistent our application response times are. Percentiles make good approximations and can be used for trend analysis, SLA agreement monitoring and daily to evaluate/troubleshoot the performance. (Lees meer..)


Tags: , , , , , , , , ,

Geplaatst: 21 May 2018

ADF Performance Tuning: Manage Your Fetched Data

In this blog I want to stress how important it is to manage the data that you fetch and load into your ADF application. I blogged on this subject earlier. It is still underestimated in my opinion. Recently I was involved in troubleshooting the performance in two different ADF projects. They had one thing in common: their servers became frequently unavailable, and they fetched far too many rows from the database. This will likely lead to memory over-consumption, ‘stop the world’ garbage collections that can run far too long, a much slower application, or in the worst case even servers that run into an OutOfMemoryError and become unavailable.

Developing a plan to manage and monitor fetched data during the whole lifetime of your ADF application is an absolute must. Keeping your sessions small is indispensable to your performance success. This blog shows a few examples of what can happen if you do not do that.

(Lees meer..)


Tags: , , , , , ,

Geplaatst: 23 April 2018

ADF Performance Monitor – Major New Version 7.0

We are very happy to announce that a major new version 7.0 of the ADF Performance Monitor will be available from May 2018. There are many improvements and major new features. This blog describes one of the new features; on usage statistics and performance metrics of end-user click actions.

A click action is the start trigger event of an HTTP request by the browser, by an action that a user takes within the UI. These are most often physical clicks of end-users on UI elements such as buttons, links, icons, charts, and tabs. But it can also be scrolling and selection events on tables, rendering of charts, polling events, auto-submits of input fields and much more. With monitoring by click action you get insight in the click actions that have the worst performance, that cause most errors, that are used most frequently, e.g. You can see in which layer (database, webservice, application server, network, browser) the total execution time has been spent. You can SLA monitor the business functions that are behind the click actions – from the perspective of the end-user. (Lees meer..)


Tags: , , , , ,

Geplaatst: 18 February 2018

ADF Performance Tuning: Avoid a Long Browser Load Time

It is not always easy to troubleshoot ADF performance problems – it is often complicated. Many parts needs to be measured, analyzed and considered. While looking for performance problems at the usual suspects (ADF application, database, network), the real problem can also be found in the often overlooked browser load time. The browser load time is just an important part of the HTTP request and response handling as is the time spent in the applicationserver, database and network. The browser load time can take a few seconds extra time on top of the server and network process time before the end-user receives the HTTP response and can continue with his work. Especially if the browser needs to build a very very ‘rich’ ADF page – the browser needs to build and process the very large DOM-tree. The end-user needs to wait then for seconds, even in modern browsers as Google Chrome, Firefox and Microsoft Edge. Often this is caused by a ‘bad’ page design where too much ADF components are rendered and displayed at the same time; too many table columns and rows, but also too many other components can cause a slow browser load time. This blog shows an example, analyses the browser load time in the ADF Performance Monitor, and suggest simple page design considerations to prevent a large browser load time.

(Lees meer..)


Tags: , ,